playhead-cli 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +9 -6
- package/README.md +43 -7
- package/action.yml +56 -2
- package/dist/audio/mux.d.ts +2 -0
- package/dist/audio/mux.d.ts.map +1 -1
- package/dist/authoring/author.d.ts +8 -2
- package/dist/authoring/author.d.ts.map +1 -1
- package/dist/authoring/catalog.d.ts.map +1 -1
- package/dist/authoring/explore.d.ts.map +1 -1
- package/dist/authoring/validate.d.ts.map +1 -1
- package/dist/bundle/types.d.ts +2 -0
- package/dist/bundle/types.d.ts.map +1 -1
- package/dist/bundle/writer.d.ts +6 -1
- package/dist/bundle/writer.d.ts.map +1 -1
- package/dist/capture/driver-api.d.ts +14 -1
- package/dist/capture/driver-api.d.ts.map +1 -1
- package/dist/capture/events.d.ts +1 -1
- package/dist/capture/events.d.ts.map +1 -1
- package/dist/capture/executor.d.ts.map +1 -1
- package/dist/capture/playwright-driver.d.ts +22 -2
- package/dist/capture/playwright-driver.d.ts.map +1 -1
- package/dist/cli/index.js +1969 -514
- package/dist/cli/index.js.map +1 -1
- package/dist/compose/camera/interpolate.d.ts +16 -3
- package/dist/compose/camera/interpolate.d.ts.map +1 -1
- package/dist/compose/camera/planner.d.ts.map +1 -1
- package/dist/compose/captions.d.ts.map +1 -1
- package/dist/compose/index.d.ts.map +1 -1
- package/dist/compose/overlays/build.d.ts.map +1 -1
- package/dist/compose/overlays/draw.d.ts.map +1 -1
- package/dist/compose/render/encoder.d.ts.map +1 -1
- package/dist/compose/render/frameStore.d.ts.map +1 -1
- package/dist/compose/render/renderer.d.ts.map +1 -1
- package/dist/compose/timeline/pacing.d.ts +4 -0
- package/dist/compose/timeline/pacing.d.ts.map +1 -1
- package/dist/compose/types.d.ts +14 -3
- package/dist/compose/types.d.ts.map +1 -1
- package/dist/index.js +1299 -382
- package/dist/index.js.map +1 -1
- package/dist/mcp/bin.js +1833 -726
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/shared/version.d.ts +0 -2
- package/dist/shared/version.d.ts.map +1 -1
- package/dist/spec/locators.d.ts.map +1 -1
- package/dist/spec/parse.d.ts.map +1 -1
- package/dist/spec/schema.d.ts +263 -2
- package/dist/spec/schema.d.ts.map +1 -1
- package/dist/verify/checks.d.ts.map +1 -1
- package/dist/verify/report.d.ts +33 -6
- package/dist/verify/report.d.ts.map +1 -1
- package/dist/verify/runner.d.ts +1 -1
- package/dist/verify/runner.d.ts.map +1 -1
- package/dist/verify/types.d.ts +36 -4
- package/dist/verify/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/spec/parse.ts","../src/spec/schema.ts","../src/spec/locators.ts","../src/capture/executor.ts","../src/capture/playwright-driver.ts","../src/shared/easing.ts","../src/shared/log.ts","../src/bundle/writer.ts","../src/bundle/hash.ts","../src/shared/version.ts","../src/shared/geometry.ts","../src/shared/exit.ts","../src/bundle/reader.ts","../src/compose/index.ts","../src/theme/index.ts","../src/compose/types.ts","../src/compose/kinds.ts","../src/capture/events.ts","../src/audio/timing.ts","../src/compose/timeline/pacing.ts","../src/compose/camera/interpolate.ts","../src/compose/camera/planner.ts","../src/compose/cursor/path.ts","../src/compose/captions.ts","../src/compose/overlays/text.ts","../src/compose/overlays/build.ts","../src/compose/render/renderer.ts","../src/compose/cursor/render.ts","../src/compose/overlays/draw.ts","../src/compose/render/frameStore.ts","../src/compose/render/encoder.ts","../src/shared/ffmpeg.ts","../src/audio/tts.ts","../src/audio/mux.ts","../src/verify/runner.ts","../src/verify/media.ts","../src/verify/checks.ts","../src/verify/contact-sheet.ts","../src/verify/vision.ts","../src/verify/report.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { dirname, resolve as resolvePath } from 'node:path';\nimport { parseDocument, LineCounter, type Document } from 'yaml';\nimport { z } from 'zod';\nimport { specSchema, editDistance, type Spec } from './schema.js';\n\nexport class SpecError extends Error {\n constructor(\n message: string,\n public readonly issues: string[] = [],\n ) {\n super(message);\n }\n}\n\n/** Every key the schema knows, for \"did you mean\" suggestions on unrecognized keys. */\nconst KNOWN_KEYS = [\n 'playhead', 'title', 'subtitle', 'app', 'output', 'theme', 'masking', 'scenes', 'vars', 'extends',\n 'url', 'viewport', 'storageState', 'compareUrl', 'assertLoggedIn', 'environment', 'network', 'dialogs', 'settle',\n 'timezone', 'locale', 'colorScheme', 'fixedTime', 'reducedMotion', 'block', 'stub', 'har', 'status', 'body', 'contentType', 'idleMs', 'capMs',\n 'kind', 'aspect', 'resolution', 'fps', 'pacing', 'dwellScale', 'audio', 'endCard',\n 'narration', 'provider', 'voice', 'rate', 'sfx', 'music', 'file', 'gainDb',\n 'accent', 'captions',\n 'target', 'style', 'id', 'steps', 'shot', 'timeout',\n 'goto', 'click', 'dblclick', 'hover', 'type', 'press', 'select', 'scroll', 'expect', 'wait',\n 'caption', 'focus', 'mask', 'text', 'value', 'keys', 'ms', 'by', 'visible', 'hidden', 'count',\n 'for', 'state', 'x', 'y',\n];\n\nfunction suggest(key: string): string | null {\n let best: string | null = null;\n let bestD = 3;\n for (const k of KNOWN_KEYS) {\n const d = editDistance(key.toLowerCase(), k.toLowerCase());\n if (d > 0 && d < bestD) {\n bestD = d;\n best = k;\n }\n }\n return best;\n}\n\n/**\n * Parse + validate YAML text into a Spec. Supports:\n * - `vars:` — `{{name}}` interpolation across every string in the spec; values may reference\n * the environment as `${env.NAME}` or `${env.NAME:-default}`. Unknown `{{var}}` is an error.\n * - line/column positions on every validation error (mapped back to the YAML source).\n * `extends:` requires file context — use loadSpec.\n */\nexport function parseSpec(yamlText: string, sourcePath = '<inline>'): Spec {\n const lineCounter = new LineCounter();\n const doc = parseDocument(yamlText, { lineCounter, keepSourceTokens: true });\n if (doc.errors.length > 0) {\n const first = doc.errors[0]!;\n throw new SpecError(`${sourcePath}: not valid YAML — ${first.message}`);\n }\n const raw = doc.toJS() as Record<string, unknown> | null;\n if (raw && typeof raw === 'object' && 'extends' in raw) {\n throw new SpecError(`${sourcePath}: \"extends\" needs a file on disk — load the spec with loadSpec/the CLI, not inline text`);\n }\n return validateResolved(interpolate(raw, sourcePath), sourcePath, doc, lineCounter);\n}\n\n/** Load a spec file, resolving `extends:` (base file merged under this one) and `vars:`. */\nexport async function loadSpec(path: string): Promise<Spec> {\n const merged = await loadRaw(resolvePath(path), 0);\n // Re-parse the LEAF file for position mapping: merged keys that came from a base file simply\n // won't have positions, which is the honest best effort for multi-file specs.\n const text = await readFile(resolvePath(path), 'utf8');\n const lineCounter = new LineCounter();\n const doc = parseDocument(text, { lineCounter });\n return validateResolved(interpolate(merged, path), path, doc, lineCounter);\n}\n\n/** Read a YAML file to a plain object, recursively merging its `extends:` base underneath it. */\nasync function loadRaw(path: string, depth: number): Promise<Record<string, unknown>> {\n if (depth > 4) throw new SpecError(`${path}: extends chain deeper than 4 — check for a cycle`);\n const text = await readFile(path, 'utf8');\n const doc = parseDocument(text);\n if (doc.errors.length > 0) throw new SpecError(`${path}: not valid YAML — ${doc.errors[0]!.message}`);\n const raw = (doc.toJS() ?? {}) as Record<string, unknown>;\n const base = raw.extends;\n delete raw.extends;\n if (base === undefined) return raw;\n if (typeof base !== 'string') throw new SpecError(`${path}: \"extends\" must be a path string`);\n const baseObj = await loadRaw(resolvePath(dirname(path), base), depth + 1);\n return mergeSpecs(baseObj, raw);\n}\n\n/** Merge rule: objects merge deep, scalars in the child win, `masking`/`scenes` arrays append\n * (base first), any other array is replaced by the child's. */\nfunction mergeSpecs(base: Record<string, unknown>, child: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...base };\n for (const [k, v] of Object.entries(child)) {\n const b = out[k];\n if (Array.isArray(b) && Array.isArray(v) && (k === 'masking' || k === 'scenes')) {\n out[k] = [...b, ...v];\n } else if (isPlainObject(b) && isPlainObject(v)) {\n out[k] = mergeSpecs(b, v);\n } else {\n out[k] = v;\n }\n }\n return out;\n}\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/** Resolve `vars:` (+ `${env.X[:-default]}` in their values) and interpolate `{{name}}` across\n * every string in the document. Fails loudly on an unknown var or unset env with no default —\n * a URL that silently renders \"undefined\" is worse than a parse error. */\nfunction interpolate(raw: unknown, sourcePath: string): unknown {\n if (!isPlainObject(raw)) return raw;\n const varsIn = isPlainObject(raw.vars) ? raw.vars : {};\n const vars = new Map<string, string>();\n for (const [name, value] of Object.entries(varsIn)) {\n vars.set(name, resolveEnv(String(value), sourcePath));\n }\n const doc = { ...raw };\n delete doc.vars;\n\n const seen = (s: string): string => {\n const withEnv = resolveEnv(s, sourcePath);\n return withEnv.replace(/\\{\\{\\s*([a-zA-Z0-9_.-]+)\\s*\\}\\}/g, (_, name: string) => {\n const v = vars.get(name);\n if (v === undefined) {\n const near = suggest(name) ?? [...vars.keys()].find((k) => editDistance(k, name) <= 2);\n throw new SpecError(\n `${sourcePath}: unknown variable {{${name}}}${near ? ` — did you mean {{${near}}}?` : ''} (declared vars: ${[...vars.keys()].join(', ') || 'none'})`,\n );\n }\n return v;\n });\n };\n const walk = (v: unknown): unknown => {\n if (typeof v === 'string') return seen(v);\n if (Array.isArray(v)) return v.map(walk);\n if (isPlainObject(v)) return Object.fromEntries(Object.entries(v).map(([k, val]) => [k, walk(val)]));\n return v;\n };\n return walk(doc);\n}\n\n/** `${env.NAME}` / `${env.NAME:-default}` → the environment value (or default). */\nfunction resolveEnv(s: string, sourcePath: string): string {\n return s.replace(/\\$\\{env\\.([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\\}/g, (_, name: string, dflt?: string) => {\n const v = process.env[name];\n if (v !== undefined) return v;\n if (dflt !== undefined) return dflt;\n throw new SpecError(`${sourcePath}: environment variable ${name} is not set and has no default (use \\${env.${name}:-fallback})`);\n });\n}\n\nfunction validateResolved(\n resolved: unknown,\n sourcePath: string,\n doc: Document,\n lineCounter: LineCounter,\n): Spec {\n const result = specSchema.safeParse(resolved);\n if (!result.success) {\n const issues = result.error.issues.map((iss) => formatIssue(iss, sourcePath, doc, lineCounter));\n throw new SpecError(`${sourcePath}: invalid spec\\n - ${issues.join('\\n - ')}`, issues);\n }\n return result.data;\n}\n\nfunction formatIssue(\n iss: z.core.$ZodIssue,\n sourcePath: string,\n doc: Document,\n lineCounter: LineCounter,\n): string {\n const where = iss.path.length ? humanPath(iss.path) : 'spec';\n const pos = positionOf(iss.path, doc, lineCounter);\n const at = pos ? `${sourcePath}:${pos.line}:${pos.col} ` : '';\n // Strict-mode \"unrecognized key\" errors get a nearest-known-key suggestion, so a typo like\n // `acent:` reads as \"did you mean accent?\" instead of a bare rejection.\n if (iss.code === 'unrecognized_keys') {\n const keys = (iss as { keys: string[] }).keys;\n const hints = keys\n .map((k) => ({ k, near: suggest(k) }))\n .map((h) => (h.near ? `\"${h.k}\" (did you mean \"${h.near}\"?)` : `\"${h.k}\"`))\n .join(', ');\n return `${at}${where}: unknown key${keys.length > 1 ? 's' : ''} ${hints}`;\n }\n return `${at}${where}: ${iss.message}`;\n}\n\n/** YAML source position for a Zod issue path (walking as deep as the leaf document allows). */\nfunction positionOf(\n path: PropertyKey[],\n doc: Document,\n lineCounter: LineCounter,\n): { line: number; col: number } | null {\n for (let depth = path.length; depth > 0; depth--) {\n try {\n const node = doc.getIn(path.slice(0, depth) as (string | number)[], true) as\n | { range?: [number, number, number] }\n | undefined;\n if (node?.range) {\n const pos = lineCounter.linePos(node.range[0]);\n return { line: pos.line, col: pos.col };\n }\n } catch {\n /* keep walking up */\n }\n }\n return null;\n}\n\nfunction humanPath(path: PropertyKey[]): string {\n // scenes.0.steps.2 → scenes[0].steps[2]\n return path\n .map((seg, i) => (typeof seg === 'number' ? `[${seg}]` : i === 0 ? String(seg) : `.${String(seg)}`))\n .join('');\n}\n","import { z } from 'zod';\nimport { parseLocator } from './locators.js';\n\n/** \"1280x800\" → {w, h} */\nconst dimensions = z\n .string()\n .regex(/^\\d+x\\d+$/, 'expected WIDTHxHEIGHT, e.g. 1280x800')\n .transform((s) => {\n const [w, h] = s.split('x').map(Number);\n return { w: w!, h: h! };\n });\n\nconst locatorString = z.string().min(1).superRefine((val, ctx) => {\n try {\n parseLocator(val);\n } catch (e) {\n ctx.addIssue({ code: 'custom', message: (e as Error).message });\n }\n});\n\nconst focusHint = z.union([z.literal('target'), z.literal('wide'), locatorString]);\n\n/** Per-step extras shared by every action. */\nconst EXTRA_KEYS = ['caption', 'narration', 'focus', 'mask', 'shot', 'timeout'] as const;\n\n/** Common optional step fields. */\nconst stepExtras = {\n caption: z.string().optional(),\n /** The SPOKEN line for TTS narration — unconstrained by the caption card's size. Resolution:\n * spoken = narration ?? caption ?? auto; on-screen card = caption ?? auto. */\n narration: z.string().optional(),\n focus: focusHint.optional(),\n /** Camera-shot boundary control: 'cut' forces this step into its own shot; 'continue' merges\n * it into the previous shot even when the heuristic would split. Decouples camera cuts from\n * scene structure (scenes stay narrative). */\n shot: z.enum(['cut', 'continue']).optional(),\n /** Per-step budget override (ms) for finding the target / meeting the expectation. */\n timeout: z.number().int().positive().optional(),\n};\n\nconst targetOrShorthand = z.union([\n locatorString,\n z.object({ target: locatorString, ...stepExtras }),\n]);\n\n// ---- normalized step forms (the discriminated union everything downstream consumes) ----\n\n// Every step variant is .strict(): an unknown field inside a step payload (a typo like `txet:`,\n// or a knob that doesn't exist like `zoom:`) must FAIL LOUDLY — silently dropping it makes a\n// misspelled option indistinguishable from a feature that works badly.\nconst gotoStep = z.object({ action: z.literal('goto'), url: z.string(), ...stepExtras }).strict();\nconst pointerStep = z\n .object({\n action: z.enum(['click', 'dblclick', 'hover']),\n target: locatorString,\n ...stepExtras,\n })\n .strict();\nconst typeStep = z\n .object({\n action: z.literal('type'),\n target: locatorString,\n text: z.string(),\n mask: z.boolean().default(false),\n ...stepExtras,\n })\n .strict();\nconst pressStep = z.object({ action: z.literal('press'), keys: z.string(), ...stepExtras }).strict();\nconst selectStep = z\n .object({\n action: z.literal('select'),\n target: locatorString,\n value: z.string(),\n ...stepExtras,\n })\n .strict();\nconst scrollStep = z\n .object({\n action: z.literal('scroll'),\n target: locatorString.optional(),\n by: z.object({ x: z.number().default(0), y: z.number() }).strict().optional(),\n ...stepExtras,\n })\n .strict();\nconst expectStep = z\n .object({\n action: z.literal('expect'),\n target: locatorString,\n visible: z.boolean().optional(),\n text: z.string().optional(),\n /** Exact number of matching elements (e.g. rows in a filtered table). */\n count: z.number().int().min(0).optional(),\n ...stepExtras,\n })\n .strict();\n/** `wait: <ms>` is the discouraged blind sleep; `wait: { for: <locator>, state?, timeout? }`\n * is the structured form — wait until an element is visible/hidden, never a fixed nap. */\nconst waitStep = z\n .object({\n action: z.literal('wait'),\n ms: z.number().int().positive().optional(),\n for: locatorString.optional(),\n state: z.enum(['visible', 'hidden']).default('visible'),\n ...stepExtras,\n })\n .strict()\n .refine((s) => (s.ms !== undefined) !== (s.for !== undefined), {\n message: 'wait needs exactly one of `ms` (blind sleep, discouraged) or `for` (an element to wait on)',\n });\n\nexport const stepSchema = z.discriminatedUnion('action', [\n gotoStep,\n pointerStep,\n typeStep,\n pressStep,\n selectStep,\n scrollStep,\n expectStep,\n waitStep,\n]);\n\nexport type Step = z.infer<typeof stepSchema>;\n\n// ---- YAML authoring form: `- click: '...'` / `- type: { target, text }` with optional sibling keys ----\n\nconst ACTION_KEYS = ['goto', 'click', 'dblclick', 'hover', 'type', 'press', 'select', 'scroll', 'expect', 'wait'] as const;\n\nconst authoredStep = z\n .record(z.string(), z.unknown())\n .superRefine((obj, ctx) => {\n const actions = ACTION_KEYS.filter((k) => k in obj);\n if (actions.length !== 1) {\n // Echo what the author actually wrote and suggest the nearest action — \"expected one of\n // ten actions\" with no mention of the offending key forces a by-eye diff of the file.\n const unknown = Object.keys(obj).filter((k) => !(EXTRA_KEYS as readonly string[]).includes(k));\n const hints = unknown\n .map((k) => ({ k, near: nearestAction(k) }))\n .filter((h): h is { k: string; near: string } => h.near !== null)\n .map((h) => ` — did you mean \"${h.near}\" instead of \"${h.k}\"?`)\n .join('');\n ctx.addIssue({\n code: 'custom',\n message:\n actions.length === 0\n ? `Step has no action (found: ${unknown.join(', ') || 'nothing'})${hints || ` — expected one of: ${ACTION_KEYS.join(', ')}`}`\n : `Step has multiple actions (${actions.join(', ')}) — exactly one is allowed`,\n });\n return;\n }\n const known = new Set<string>([...ACTION_KEYS, ...EXTRA_KEYS]);\n for (const key of Object.keys(obj)) {\n if (!known.has(key)) {\n ctx.addIssue({ code: 'custom', message: `Unknown step field \"${key}\"` });\n }\n }\n })\n .transform((obj) => normalizeStep(obj));\n\n/** Nearest valid action to a typo (edit distance ≤ 2), or null. */\nfunction nearestAction(key: string): string | null {\n let best: string | null = null;\n let bestD = 3;\n for (const a of ACTION_KEYS) {\n const d = editDistance(key.toLowerCase(), a);\n if (d < bestD) {\n bestD = d;\n best = a;\n }\n }\n return best;\n}\n\nexport function editDistance(a: string, b: string): number {\n const dp = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)] as number[]);\n for (let j = 0; j <= b.length; j++) dp[0]![j] = j;\n for (let i = 1; i <= a.length; i++) {\n for (let j = 1; j <= b.length; j++) {\n dp[i]![j] = Math.min(\n dp[i - 1]![j]! + 1,\n dp[i]![j - 1]! + 1,\n dp[i - 1]![j - 1]! + (a[i - 1] === b[j - 1] ? 0 : 1),\n );\n }\n }\n return dp[a.length]![b.length]!;\n}\n\nfunction normalizeStep(obj: Record<string, unknown>): unknown {\n const action = ACTION_KEYS.find((k) => k in obj)!;\n const payload = obj[action];\n const extras: Record<string, unknown> = {};\n for (const k of EXTRA_KEYS) {\n if (k in obj) extras[k] = obj[k];\n }\n\n if (typeof payload === 'string') {\n // shorthand value: locator for element actions, url for goto, keys for press\n if (action === 'goto') return { action, url: payload, ...extras };\n if (action === 'press') return { action, keys: payload, ...extras };\n return { action, target: payload, ...extras };\n }\n if (typeof payload === 'number' && action === 'wait') {\n return { action, ms: payload, ...extras };\n }\n if (payload !== null && typeof payload === 'object') {\n return { action, ...(payload as Record<string, unknown>), ...extras };\n }\n return { action, value: payload, ...extras };\n}\n\n// ---- top-level spec ----\n//\n// Every object here is .strict(): a key the schema doesn't know is an ERROR, never silently\n// dropped. The spec must mean what it says — an author must be able to tell \"I configured this\n// wrong\" apart from \"this configuration does nothing\".\n\nexport const specSchema = z\n .object({\n playhead: z.literal(1),\n title: z.string().min(1),\n /** Title-card subtitle. Defaults to the app's host — set this for anything shareable. */\n subtitle: z.string().optional(),\n app: z\n .object({\n url: z.string().url(),\n /** Capture viewport. When omitted it is derived from output.aspect so portrait/square\n * outputs are captured at a matching viewport (the app reflows natively, no cropping). */\n viewport: dimensions.optional(),\n storageState: z.string().optional(),\n /** Fail fast when auth is stale: this locator must match after the initial load, or the\n * capture aborts — instead of confidently filming the login page. */\n assertLoggedIn: locatorString.optional(),\n /** For before/after: a second app to capture the same flow against (the \"before\"). */\n compareUrl: z.string().url().optional(),\n /** Determinism controls: same spec → same pixels regardless of where/when it runs. */\n environment: z\n .object({\n timezone: z.string().optional(),\n locale: z.string().optional(),\n colorScheme: z.enum(['light', 'dark']).optional(),\n /** Freeze Date at this ISO timestamp — \"3 minutes ago\" stops drifting between runs. */\n fixedTime: z.string().optional(),\n reducedMotion: z.boolean().optional(),\n })\n .strict()\n .optional(),\n /** Request interception: block third-party noise, stub responses, replay a HAR. */\n network: z\n .object({\n block: z.array(z.string()).optional(),\n stub: z\n .array(\n z\n .object({\n url: z.string(),\n status: z.number().int().optional(),\n body: z.string().optional(),\n contentType: z.string().optional(),\n })\n .strict(),\n )\n .optional(),\n har: z.string().optional(),\n })\n .strict()\n .optional(),\n /** window.confirm()/alert() policy. Default accept — the silent auto-dismiss films the\n * cancel branch of confirm-guarded flows. */\n dialogs: z.enum(['accept', 'dismiss']).optional(),\n /** Settle tuning for slow backends / chatty apps. */\n settle: z\n .object({\n idleMs: z.number().int().positive().optional(),\n capMs: z.number().int().positive().optional(),\n })\n .strict()\n .optional(),\n })\n .strict(),\n output: z\n .object({\n kind: z\n .enum(['walkthrough', 'demo', 'bug-repro', 'before-after', 'release', 'social'])\n .default('walkthrough'),\n aspect: z.enum(['16:9', '9:16', '1:1']).default('16:9'),\n /** Output resolution; when omitted it is derived from the aspect. */\n resolution: dimensions.optional(),\n fps: z.number().int().min(24).max(60).default(30),\n pacing: z.enum(['relaxed', 'normal', 'brisk']).optional(),\n /**\n * Multiplier on per-step dwell (min-step duration, post-action holds, outro).\n * 1 = the pacing preset as-is. Raise it for long-form teaching walkthroughs\n * where each screen should linger so a viewer can read and absorb it.\n */\n dwellScale: z.number().min(0.5).max(4).optional(),\n /**\n * Audio. `narration: tts` speaks each step's caption (pacing grows so every line finishes\n * before its step ends). `sfx` adds a soft synthesized click at each click beat. `music`\n * lays a user-supplied bed under everything, ducked beneath narration. Any audio work\n * finishes with loudness normalization (EBU R128, I=-16).\n */\n audio: z\n .object({\n narration: z.enum(['none', 'tts']).default('none'),\n // 'say' — macOS built-in (zero deps, Mac-only, robotic).\n // 'kokoro' — natural neural voice, offline, cross-platform; needs the optional\n // kokoro-js package (npm i kokoro-js). Voices: af_heart (default), am_michael, …\n provider: z.enum(['say', 'kokoro']).default('say'),\n voice: z.string().optional(),\n rate: z.number().int().min(80).max(400).optional(),\n /** Click sound effects at click/select beats. Defaults on when this block is present. */\n sfx: z.boolean().default(true),\n /** Music bed from a local audio file (no asset is bundled — bring your own licensed track). */\n music: z\n .object({\n file: z.string(),\n gainDb: z.number().min(-40).max(6).default(-19),\n })\n .strict()\n .optional(),\n })\n .strict()\n // The kokoro voice set is deliberately limited to two curated, natural voices —\n // Heart (default) and Michael. Aliases 'heart'/'michael' are accepted.\n .refine(\n (a) =>\n a.provider !== 'kokoro' ||\n a.voice === undefined ||\n ['heart', 'af_heart', 'michael', 'am_michael'].includes(a.voice),\n { message: \"kokoro voice must be 'heart' (default) or 'michael'\", path: ['voice'] },\n )\n .optional(),\n /** Closing card. When set, the video ends on a title-card-styled end card. */\n endCard: z\n .object({\n title: z.string().min(1),\n subtitle: z.string().optional(),\n })\n .strict()\n .optional(),\n })\n .strict()\n .prefault({}),\n // No `name` field: exactly one theme exists today, and a knob that is accepted but ignored is\n // a lie. It returns when a theme registry does.\n theme: z\n .object({\n accent: z\n .string()\n .regex(/^#[0-9a-fA-F]{6}$/, 'expected a #rrggbb hex color')\n .optional(),\n captions: z.enum(['bottom', 'top', 'off']).default('bottom'),\n })\n .strict()\n .prefault({}),\n masking: z\n .array(\n z\n .object({\n target: locatorString,\n style: z.enum(['solid', 'blur']).default('solid'),\n })\n .strict(),\n )\n .default([]),\n scenes: z\n .array(\n z\n .object({\n id: z.string().regex(/^[a-z0-9][a-z0-9-]*$/, 'scene ids are lowercase kebab-case'),\n title: z.string().optional(),\n steps: z.array(authoredStep.pipe(stepSchema)).min(1),\n })\n .strict(),\n )\n .min(1),\n })\n .strict();\n\nexport type Spec = z.infer<typeof specSchema>;\nexport type Scene = Spec['scenes'][number];\nexport type OutputSettings = Spec['output'];\nexport type MaskRule = Spec['masking'][number];\nexport type OutputKind = Spec['output']['kind'];\nexport type Aspect = Spec['output']['aspect'];\n\n/** Capture viewport + output resolution for each aspect (portrait/square reflow, never crop). */\nexport const ASPECTS: Record<Aspect, { viewport: { w: number; h: number }; resolution: { w: number; h: number } }> = {\n '16:9': { viewport: { w: 1280, h: 720 }, resolution: { w: 1920, h: 1080 } },\n '9:16': { viewport: { w: 720, h: 1280 }, resolution: { w: 1080, h: 1920 } },\n '1:1': { viewport: { w: 900, h: 900 }, resolution: { w: 1080, h: 1080 } },\n};\n\n/** The capture viewport: explicit spec value, else derived from the output aspect. */\nexport function resolveViewport(spec: Spec): { w: number; h: number } {\n return spec.app.viewport ?? ASPECTS[spec.output.aspect].viewport;\n}\n\n/** The output resolution: explicit spec value, else derived from the aspect. */\nexport function resolveResolution(spec: Spec): { w: number; h: number } {\n return spec.output.resolution ?? ASPECTS[spec.output.aspect].resolution;\n}\n\n/** A step with its position in the spec — the unit the capture executor and compositor work in. */\nexport interface AddressedStep {\n sceneId: string;\n sceneIndex: number;\n stepIndex: number;\n /** Global 1-based index across all scenes, used for step numbering. */\n ordinal: number;\n step: Step;\n}\n\nexport function flattenSteps(spec: Spec): AddressedStep[] {\n const out: AddressedStep[] = [];\n let ordinal = 0;\n spec.scenes.forEach((scene, sceneIndex) => {\n scene.steps.forEach((step, stepIndex) => {\n ordinal += 1;\n out.push({ sceneId: scene.id, sceneIndex, stepIndex, ordinal, step });\n });\n });\n return out;\n}\n","/**\n * Playhead locator grammar — resilient, label/role-based element addressing.\n *\n * role=button[name=\"Add user\"] role + accessible name\n * role=cell[name=/api key/i] regex accessible name\n * label=Email form control by label\n * text=\"User added\" visible text\n * placeholder=Search input placeholder\n * testid=add-user data-testid\n * css=#legacy .thing escape hatch (warned)\n * ... >> nth=1 pick among multiple matches\n * frame=#preview >> role=button[name=\"Save\"] pierce into an iframe (chainable)\n * frame=iframe[name=a] >> frame=#inner >> text=\"Hi\" nested frames\n *\n * Parsed form is serializable (regexes stored as {source, flags}) so it can live\n * in spec.resolved.json and events.json.\n */\n\nexport interface RegexSpec {\n source: string;\n flags: string;\n}\n\nexport type TextMatch = { exact: string } | { substring: string } | { regex: RegexSpec };\n\nexport type LocatorBase =\n | { kind: 'role'; role: string; name?: TextMatch }\n | { kind: 'label'; match: TextMatch }\n | { kind: 'text'; match: TextMatch }\n | { kind: 'placeholder'; match: TextMatch }\n | { kind: 'testid'; value: string }\n | { kind: 'css'; selector: string };\n\nexport interface ParsedLocator {\n base: LocatorBase;\n nth?: number;\n /** CSS selectors of the iframe chain to pierce (outermost first) before resolving `base`. */\n frames?: string[];\n /** The original spec string, kept for captions/diagnostics. */\n raw: string;\n}\n\nexport class LocatorParseError extends Error {}\n\nexport function parseLocator(input: string): ParsedLocator {\n const raw = input.trim();\n let nth: number | undefined;\n\n // Segments: [frame=SEL ...] BASE [nth=N]\n const parts = raw.split('>>').map((p) => p.trim());\n const frames: string[] = [];\n while (parts.length > 0 && parts[0]!.startsWith('frame=')) {\n const sel = unquote(parts.shift()!.slice('frame='.length).trim());\n if (!sel) throw new LocatorParseError(`Empty frame selector in \"${raw}\"`);\n frames.push(sel);\n }\n if (parts.length === 0) {\n throw new LocatorParseError(`Locator \"${raw}\" has frames but no element — add a base like role=... after the frame chain`);\n }\n const body = parts.shift()!;\n if (parts.length > 0) {\n const tail = parts.join(' >> ');\n const m = /^nth=(\\d+)$/.exec(tail);\n if (!m) throw new LocatorParseError(`Unsupported locator suffix \"${tail}\" in \"${raw}\" (only \"nth=N\" is supported)`);\n nth = Number(m[1]);\n }\n const withFrames = (p: ParsedLocator): ParsedLocator => (frames.length > 0 ? { ...p, frames } : p);\n\n const eq = body.indexOf('=');\n if (eq === -1) {\n throw new LocatorParseError(\n `Locator \"${raw}\" is missing an engine prefix — expected role=, label=, text=, placeholder=, testid= or css=`,\n );\n }\n const engine = body.slice(0, eq).trim();\n const rest = body.slice(eq + 1).trim();\n\n switch (engine) {\n case 'role': {\n const m = /^([\\w-]+)(?:\\[name=(.+)\\])?$/.exec(rest);\n if (!m) throw new LocatorParseError(`Malformed role locator \"${raw}\" — expected role=button[name=\"...\"]`);\n const base: LocatorBase = { kind: 'role', role: m[1]! };\n if (m[2] !== undefined) base.name = parseTextMatch(m[2]!, raw);\n return withFrames({ base, nth, raw });\n }\n case 'label':\n return withFrames({ base: { kind: 'label', match: parseTextMatch(rest, raw) }, nth, raw });\n case 'text':\n return withFrames({ base: { kind: 'text', match: parseTextMatch(rest, raw) }, nth, raw });\n case 'placeholder':\n return withFrames({ base: { kind: 'placeholder', match: parseTextMatch(rest, raw) }, nth, raw });\n case 'testid': {\n if (!rest) throw new LocatorParseError(`Empty testid in locator \"${raw}\"`);\n return withFrames({ base: { kind: 'testid', value: unquote(rest) }, nth, raw });\n }\n case 'css': {\n if (!rest) throw new LocatorParseError(`Empty css selector in locator \"${raw}\"`);\n return withFrames({ base: { kind: 'css', selector: rest }, nth, raw });\n }\n default:\n throw new LocatorParseError(\n `Unknown locator engine \"${engine}\" in \"${raw}\" — expected role, label, text, placeholder, testid or css`,\n );\n }\n}\n\nfunction parseTextMatch(s: string, context: string): TextMatch {\n const v = s.trim();\n if (v.startsWith('/')) {\n const m = /^\\/(.+)\\/([a-z]*)$/.exec(v);\n if (!m) throw new LocatorParseError(`Malformed regex \"${v}\" in locator \"${context}\"`);\n try {\n new RegExp(m[1]!, m[2]!);\n } catch {\n throw new LocatorParseError(`Invalid regex \"${v}\" in locator \"${context}\"`);\n }\n return { regex: { source: m[1]!, flags: m[2]! } };\n }\n if ((v.startsWith('\"') && v.endsWith('\"') && v.length >= 2) || (v.startsWith(\"'\") && v.endsWith(\"'\") && v.length >= 2)) {\n return { exact: v.slice(1, -1) };\n }\n if (!v) throw new LocatorParseError(`Empty text match in locator \"${context}\"`);\n return { substring: v };\n}\n\nfunction unquote(s: string): string {\n if ((s.startsWith('\"') && s.endsWith('\"')) || (s.startsWith(\"'\") && s.endsWith(\"'\"))) return s.slice(1, -1);\n return s;\n}\n\n/** Human-readable form of what a locator points at, used for captions when the accessible name is unavailable. */\nexport function locatorDisplayName(loc: ParsedLocator): string {\n const b = loc.base;\n switch (b.kind) {\n case 'role':\n return b.name ? textMatchDisplay(b.name) : b.role;\n case 'label':\n case 'text':\n case 'placeholder':\n return textMatchDisplay(b.match);\n case 'testid':\n return b.value;\n case 'css':\n return b.selector;\n }\n}\n\nfunction textMatchDisplay(m: TextMatch): string {\n if ('exact' in m) return m.exact;\n if ('substring' in m) return m.substring;\n return m.regex.source;\n}\n","import { join } from 'node:path';\nimport type { Spec, AddressedStep } from '../spec/schema.js';\nimport { flattenSteps, resolveViewport } from '../spec/schema.js';\nimport { parseLocator } from '../spec/locators.js';\nimport type { Driver, MaskInstruction } from './driver-api.js';\nimport { PlaywrightDriver } from './playwright-driver.js';\nimport type { ActionEvent, CaptureEvent, CursorWaypoint, EventLog, TargetInfo } from './events.js';\nimport { BundleWriter } from '../bundle/writer.js';\nimport { rectCenter, clamp, dist } from '../shared/geometry.js';\nimport { log } from '../shared/log.js';\nimport { FlowError } from '../shared/exit.js';\n\nexport interface CaptureOptions {\n outDir: string;\n headless?: boolean;\n captureFormat?: 'jpeg' | 'png';\n quality?: number;\n driver?: Driver;\n /**\n * Iteration accelerator: steps BEFORE this scene run fast (no cursor choreography, no\n * filming, no events) purely to build app state; capture starts at this scene. The bundle\n * is a partial covering only the filmed scenes — for iterating on one scene, not shipping.\n */\n fromScene?: string;\n}\n\nconst SETTLE = { idleMs: 300, capMs: 5000 };\nconst TARGET_TIMEOUT_MS = 10_000;\nconst EXPECT_TIMEOUT_MS = 10_000;\nconst TYPE_DELAY_MS = 45;\n/** Hard budget for one step end-to-end (resolve + cursor + action). A step that can't finish in\n * this window is failed with its stepRef instead of hanging the whole capture. */\nconst STEP_BUDGET_MS = 45_000;\n/** Watchdog: overall capture deadline. Long specs are bounded per-step anyway; this is the\n * backstop that guarantees a capture NEVER runs unbounded (the 7-minute-hang class). */\nconst CAPTURE_DEADLINE_MS = 10 * 60_000;\n\nexport async function capture(spec: Spec, opts: CaptureOptions): Promise<{ bundleDir: string }> {\n const bundleDir = join(opts.outDir, 'capture');\n const driver = opts.driver ?? new PlaywrightDriver();\n const dpr = 2;\n const format = opts.captureFormat ?? 'jpeg';\n const writer = new BundleWriter(bundleDir, format);\n const events: CaptureEvent[] = [];\n const maskRules: MaskInstruction[] = spec.masking.map((m) => ({\n loc: parseLocator(m.target),\n style: m.style,\n }));\n\n const viewport = resolveViewport(spec);\n const settleCfg = {\n idleMs: spec.app.settle?.idleMs ?? SETTLE.idleMs,\n capMs: spec.app.settle?.capMs ?? SETTLE.capMs,\n };\n log.info(`capturing \"${spec.title}\" from ${spec.app.url}`);\n await driver.launch({\n viewport,\n dpr,\n headless: opts.headless ?? true,\n ...(spec.app.storageState ? { storageStatePath: spec.app.storageState } : {}),\n ...(spec.app.environment ? { environment: spec.app.environment } : {}),\n ...(spec.app.network ? { network: spec.app.network } : {}),\n ...(spec.app.dialogs ? { dialogs: spec.app.dialogs } : {}),\n });\n\n // Clock scaffolding lives OUTSIDE the try so the finally can finalize the bundle: a failed\n // step must never destroy the footage already captured (the failure is when video evidence\n // matters most). t0 is re-based after clock sync below.\n let t0 = Date.now();\n const rel = (nodeMs: number) => nodeMs - t0;\n const now = () => rel(Date.now());\n let clockOffsetMs = 0;\n let failure: { stepRef: string; message: string } | undefined;\n let currentStepRef = '';\n\n try {\n clockOffsetMs = await driver.measureClockOffset();\n t0 = Date.now();\n\n driver.onNavigation((url, tNode) => {\n events.push({ type: 'navigation', url, t: rel(tNode) });\n });\n\n const startFilming = () =>\n driver.startCapture((frame) => writer.addFrame(frame.data, rel(frame.tNodeMs)), {\n format,\n quality: opts.quality ?? 82,\n scale: dpr,\n // 24 requested ≈ 20-22 achieved with the screenshot loop's ~25ms capture cost; frame\n // blending at compose smooths the rest. (True 30+ needs the screencast source — planned.)\n fps: 24,\n });\n // Filming starts up-front normally, but AFTER the fast-forward pre-roll with --from-scene:\n // pre-roll steps build state and must never appear on film.\n if (!opts.fromScene) await startFilming();\n\n // Initial navigation + masks. CSS-expressible rules also go in-page for continuous tagging,\n // so elements that appear MID-step get masked the frame they appear.\n await driver.installMaskRules(maskRules);\n await driver.goto(spec.app.url);\n await applyMasksAndSample(driver, maskRules, writer, now);\n await driver.settle(settleCfg);\n if (spec.app.assertLoggedIn) {\n // Fail FAST on stale auth instead of confidently filming the login page.\n await driver\n .expectState(parseLocator(spec.app.assertLoggedIn), { visible: true }, 8000)\n .catch(() => {\n throw new Error(\n `assertLoggedIn failed: ${spec.app.assertLoggedIn} not visible — storageState stale? Re-run: playhead login ${spec.app.url}`,\n );\n });\n }\n // Guarantee PRE-first-action footage: heavy initial loads can stall the first grabs (CDP\n // contention), and a first frame that lands after the first click makes the before-state\n // unprovable — for verification and for the viewer alike.\n if (!opts.fromScene) await driver.captureNow();\n\n let steps = flattenSteps(spec);\n const totalSteps = steps.length;\n if (opts.fromScene) {\n const idx = steps.findIndex((s) => s.sceneId === opts.fromScene);\n if (idx < 0) throw new Error(`--from-scene: no scene with id \"${opts.fromScene}\" in the spec`);\n log.info(`fast-forwarding ${idx} step(s) to scene \"${opts.fromScene}\" (state only, not filmed)`);\n for (const pre of steps.slice(0, idx)) {\n currentStepRef = `${pre.sceneId}/${pre.stepIndex} (fast-forward)`;\n await fastForwardStep(driver, pre.step);\n }\n currentStepRef = '';\n steps = steps.slice(idx);\n await driver.settle(settleCfg);\n await startFilming();\n await driver.captureNow();\n }\n\n for (const addressed of steps) {\n currentStepRef = `${addressed.sceneId}/${addressed.stepIndex}`;\n if (now() > CAPTURE_DEADLINE_MS) {\n throw new Error(`capture watchdog: exceeded ${CAPTURE_DEADLINE_MS / 60000} minutes at step ${currentStepRef}`);\n }\n log.step(`${addressed.ordinal}/${totalSteps} ${describeStep(addressed)}`);\n const event = await withStepBudget(\n executeStep(driver, addressed, { rel, now }, spec.app.url),\n STEP_BUDGET_MS,\n currentStepRef,\n );\n // Re-tag masks (new DOM may match rules), then settle.\n await applyMasksAndSample(driver, maskRules, writer, now);\n await driver.settle(settleCfg);\n // A focus HINT naming a third locator (\"click here, LOOK there\") points at the step's\n // PAYOFF — waiting for it is part of settling this step. Poll briefly: the payoff often\n // appears a beat after network-idle (the app's own mutation delay), and stamping tSettled\n // before it exists would freeze the hold on pre-payoff footage.\n const focus = 'focus' in addressed.step ? addressed.step.focus : undefined;\n if (focus && focus !== 'target' && focus !== 'wide') {\n const loc = parseLocator(focus);\n for (let i = 0; i < 10 && !event.focusTarget; i++) {\n event.focusTarget = await driver.tryMeasure(loc);\n if (!event.focusTarget) await sleep(250);\n }\n if (!event.focusTarget) {\n log.warn(`${addressed.sceneId}/${addressed.stepIndex}: focus locator never appeared: ${focus}`);\n }\n }\n await ensurePostActionFrame(driver, event.tAction, rel);\n // tSettled must point at a frame that reflects the settled state (payoff included).\n // captureNow above guarantees a fresh one, so stamp after it — even instant hash-route\n // navigations whose settle returned in ~100ms then have on-film proof of their effect.\n event.tSettled = now();\n if (event.targetPre && event.locator) {\n event.targetPost = await driver.tryMeasure(parseLocator(event.locator));\n }\n if (addressed.step.action === 'type' && addressed.step.mask && event.locator) {\n const info = await driver.tryMeasure(parseLocator(event.locator));\n if (info) writer.addMaskSample({ t: now(), rects: [{ style: 'solid', ...info.bbox }] });\n }\n events.push(event);\n }\n currentStepRef = '';\n\n // Trailing beat so the final state has footage to hold on.\n await driver.settle(settleCfg);\n await driver.captureNow();\n await sleep(400);\n return { bundleDir };\n } catch (e) {\n const message = (e as Error).message;\n failure = { stepRef: currentStepRef || '(setup)', message };\n // Failure diagnostics, best-effort: where we were and what the page looked like.\n try {\n const aria = await driver.ariaSnapshot();\n const url = driver.currentUrl();\n const { writeFile } = await import('node:fs/promises');\n await writeFile(\n join(bundleDir, 'failure.json'),\n JSON.stringify({ stepRef: failure.stepRef, message, url, at: new Date().toISOString() }, null, 2),\n );\n if (aria) await writeFile(join(bundleDir, 'failure-aria.txt'), aria);\n } catch {\n /* diagnostics are best-effort */\n }\n // A capture-time failure is the APP breaking the flow — exit code 1, not an infra error.\n throw new FlowError(\n `${message}\\n (partial bundle with ${writer.frameCount()} frames saved to ${bundleDir} — failure.json has the details)`,\n );\n } finally {\n // Finalize the bundle EVEN ON FAILURE: frames/index.json + manifest are what make the\n // captured footage openable, and a failed run's footage is the most valuable footage.\n await driver.stopCapture().catch(() => {});\n // Console/pageerror/dialog/popup evidence — what bug-repro needs and failure diagnosis reads.\n try {\n const consoleLog = driver.consoleLog();\n if (consoleLog.length > 0) {\n const { writeFile } = await import('node:fs/promises');\n await writeFile(\n join(bundleDir, 'console.json'),\n JSON.stringify(consoleLog.map((c) => ({ ...c, t: rel(c.t) })), null, 2),\n );\n }\n } catch {\n /* best-effort */\n }\n const durationMs = now();\n const eventLog: EventLog = {\n schema: 'playhead/events@1',\n meta: {\n viewport,\n dpr,\n frameW: 0, // finalized by writer from the first frame's real dimensions\n frameH: 0,\n clockOffsetMs,\n startedAtIso: new Date(t0).toISOString(),\n durationMs,\n appUrl: spec.app.url,\n },\n events,\n };\n try {\n const manifest = await writer.finish({\n spec,\n events: eventLog,\n appUrl: spec.app.url,\n viewport,\n dpr,\n clockOffsetMs,\n durationMs,\n ...(failure ? { partial: true, failure } : {}),\n });\n if (!failure) {\n log.ok(`bundle: ${manifest.frameCount} frames, ${(durationMs / 1000).toFixed(1)}s → ${bundleDir}`);\n } else {\n log.warn(`partial bundle: ${manifest.frameCount} frames up to ${failure.stepRef} → ${bundleDir}`);\n }\n } catch (finishErr) {\n log.warn(`could not finalize bundle: ${(finishErr as Error).message}`);\n }\n await driver.close();\n }\n}\n\n/** Advance app state with no filming, no cursor choreography, minimal waits (fast-forward\n * pre-roll for --from-scene). Blind `wait: ms` sleeps are skipped; expects are best-effort. */\nasync function fastForwardStep(driver: Driver, step: import('../spec/schema.js').Step): Promise<void> {\n const T = step.timeout ?? 8000;\n switch (step.action) {\n case 'goto':\n await driver.goto(step.url);\n break;\n case 'click':\n case 'dblclick': {\n const t = await driver.resolveTarget(parseLocator(step.target), T);\n await driver.clickAt(rectCenter(t.bbox), { double: step.action === 'dblclick' });\n break;\n }\n case 'hover':\n break; // no lasting state\n case 'type': {\n const t = await driver.resolveTarget(parseLocator(step.target), T);\n await driver.clickAt(rectCenter(t.bbox));\n await driver.typeText(step.text, 0);\n break;\n }\n case 'press':\n await driver.press(step.keys);\n break;\n case 'select':\n await driver.selectOption(parseLocator(step.target), step.value);\n break;\n case 'scroll':\n if (step.target) await driver.scrollIntoView(parseLocator(step.target));\n else if (step.by) await driver.scrollBy(step.by);\n await driver.waitForScrollSettle(1500);\n break;\n case 'expect':\n await driver\n .expectState(parseLocator(step.target), { ...(step.visible !== undefined ? { visible: step.visible } : {}) }, T)\n .catch(() => {});\n break;\n case 'wait':\n if (step.for) {\n await driver.expectState(parseLocator(step.for), { visible: step.state !== 'hidden' }, T).catch(() => {});\n }\n break;\n }\n await driver.settle({ idleMs: 200, capMs: 2500 });\n}\n\n/** Fail a step with its ref when it exceeds the budget, instead of hanging the capture. */\nfunction withStepBudget<T>(p: Promise<T>, ms: number, stepRef: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new Error(`step ${stepRef} exceeded its ${ms / 1000}s budget`)),\n ms,\n );\n p.then(\n (v) => { clearTimeout(timer); resolve(v); },\n (e) => { clearTimeout(timer); reject(e); },\n );\n });\n}\n\ninterface Clock {\n rel: (nodeMs: number) => number;\n now: () => number;\n}\n\nasync function executeStep(driver: Driver, addressed: AddressedStep, clock: Clock, appUrl: string): Promise<ActionEvent> {\n const { step, sceneId, stepIndex, ordinal } = addressed;\n const base: ActionEvent = {\n type: 'action',\n kind: step.action,\n sceneId,\n stepIndex,\n ordinal,\n cursorPath: [],\n tStart: clock.now(),\n tAction: 0,\n tActionEnd: 0,\n tSettled: 0,\n ...(step.caption ? { caption: step.caption } : {}),\n ...(step.narration ? { narration: step.narration } : {}),\n ...(step.shot ? { shot: step.shot } : {}),\n ...('focus' in step && step.focus ? { focus: step.focus } : {}),\n };\n // Per-step override for target-resolution / expectation budgets.\n const budgetMs = step.timeout ?? TARGET_TIMEOUT_MS;\n\n switch (step.action) {\n case 'goto': {\n // Relative URLs resolve against app.url, so a spec can say `goto: /deals` and be pointed\n // at any environment by changing one line.\n const url = new URL(step.url, appUrl).href;\n base.locator = url;\n base.tAction = clock.now();\n await driver.goto(url);\n base.tActionEnd = clock.now();\n return base;\n }\n case 'click':\n case 'dblclick':\n case 'hover': {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n const pre = await driver.resolveTarget(loc, budgetMs);\n base.targetPre = pre;\n base.cursorPath = await moveToTarget(driver, pre, clock);\n if (step.action === 'hover') {\n base.tAction = clock.now();\n base.tActionEnd = base.tAction;\n } else {\n // Cosmetic cursor is already on the target; the ACTION goes through locator.click so\n // actionability + hit-target verification + retry come for free (a raw coordinate\n // click is silently redirected by anything drifting under the point).\n const { tDown, tUp } = await driver.actClick(loc, {\n double: step.action === 'dblclick',\n timeoutMs: budgetMs,\n });\n base.tAction = clock.rel(tDown);\n base.tActionEnd = clock.rel(tUp);\n }\n return base;\n }\n case 'type': {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n const pre = await driver.resolveTarget(loc, budgetMs);\n base.targetPre = pre;\n base.cursorPath = await moveToTarget(driver, pre, clock);\n await driver.actClick(loc, { timeoutMs: budgetMs });\n if (step.mask) {\n // Tag before any keystroke lands; the overlay stays for the rest of the capture.\n await driver.setTypingMask(loc);\n }\n const { tFirst, tLast } = await driver.typeText(step.text, TYPE_DELAY_MS);\n base.tAction = clock.rel(tFirst);\n base.tActionEnd = clock.rel(tLast);\n base.masked = step.mask;\n base.typedText = step.mask ? '•'.repeat(Math.min(step.text.length, 8)) : step.text;\n return base;\n }\n case 'press': {\n base.locator = step.keys;\n const { tDown } = await driver.press(step.keys);\n base.tAction = clock.rel(tDown);\n base.tActionEnd = clock.now();\n return base;\n }\n case 'select': {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n const pre = await driver.resolveTarget(loc, budgetMs);\n base.targetPre = pre;\n base.cursorPath = await moveToTarget(driver, pre, clock);\n // No raw pre-click: it opens the native popup that nothing dismisses. selectOption\n // handles focus + change events; the cursor visit above supplies the visual beat.\n base.tAction = clock.now();\n await driver.selectOption(loc, step.value);\n base.typedText = step.value;\n base.tActionEnd = clock.now();\n return base;\n }\n case 'scroll': {\n base.tAction = clock.now();\n if (step.target) {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n await driver.scrollIntoView(loc);\n await driver.waitForScrollSettle(2500); // measure only once the scroll has stopped\n base.targetPre = await driver.tryMeasure(loc);\n } else if (step.by) {\n await driver.scrollBy(step.by);\n await driver.waitForScrollSettle(2500);\n }\n base.tActionEnd = clock.now();\n return base;\n }\n case 'expect': {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n await driver.expectState(\n loc,\n { ...(step.visible !== undefined ? { visible: step.visible } : {}), ...(step.text !== undefined ? { text: step.text } : {}), ...(step.count !== undefined ? { count: step.count } : {}) },\n step.timeout ?? EXPECT_TIMEOUT_MS,\n );\n base.targetPre = await driver.tryMeasure(loc);\n base.tAction = clock.now();\n base.tActionEnd = base.tAction;\n return base;\n }\n case 'wait': {\n base.tAction = clock.now();\n if (step.for) {\n // Structured wait: block on an element state instead of a blind sleep.\n base.locator = step.for;\n await driver.expectState(\n parseLocator(step.for),\n { visible: step.state !== 'hidden' },\n step.timeout ?? EXPECT_TIMEOUT_MS,\n );\n } else {\n await sleep(step.ms ?? 0);\n }\n base.tActionEnd = clock.now();\n return base;\n }\n }\n}\n\nasync function moveToTarget(driver: Driver, target: TargetInfo, clock: Clock): Promise<CursorWaypoint[]> {\n const to = rectCenter(target.bbox);\n const travel = clamp(250 + dist(driver.cursorPos(), to) * 0.5, 300, 700);\n const waypoints = await driver.moveCursor(to, travel);\n return waypoints.map((w) => ({ x: round1(w.x), y: round1(w.y), t: round1(clock.rel(w.t)) }));\n}\n\n/**\n * Guarantee a fresh frame reflecting the settled post-action state. Always captures one (not\n * only when footage looks stale): a fast hash-route navigation settles in ~100ms, and without a\n * forced post-settle frame the \"after\" sample can land on the pre-navigation paint.\n */\nasync function ensurePostActionFrame(\n driver: Driver,\n tAction: number,\n rel: (nodeMs: number) => number,\n): Promise<void> {\n await sleep(24); // let the post-action paint flush\n await driver.captureNow();\n if (rel(driver.lastFrameAt()) <= tAction) {\n for (let i = 0; i < 2 && rel(driver.lastFrameAt()) <= tAction; i++) {\n await sleep(40);\n await driver.captureNow();\n }\n if (rel(driver.lastFrameAt()) <= tAction) {\n log.warn(`no captured frame after action at t=${tAction.toFixed(0)}ms — footage may hold a stale frame`);\n }\n }\n}\n\nasync function applyMasksAndSample(\n driver: Driver,\n rules: MaskInstruction[],\n writer: BundleWriter,\n now: () => number,\n): Promise<void> {\n if (rules.length === 0) return;\n const rects = await driver.applyMasks(rules);\n if (rects.length > 0) writer.addMaskSample({ t: now(), rects });\n}\n\nfunction describeStep(a: AddressedStep): string {\n const s = a.step;\n switch (s.action) {\n case 'goto':\n return `goto ${s.url}`;\n case 'type':\n return `type into ${s.target}${s.mask ? ' (masked)' : ''}`;\n case 'press':\n return `press ${s.keys}`;\n case 'wait':\n return `wait ${s.ms}ms`;\n case 'scroll':\n return `scroll ${s.target ?? JSON.stringify(s.by)}`;\n default:\n return `${s.action} ${'target' in s ? s.target : ''}`;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction round1(n: number): number {\n return Math.round(n * 10) / 10;\n}\n","import { chromium, type Browser, type BrowserContext, type Page, type CDPSession, type Locator, type FrameLocator } from 'playwright';\nimport type {\n Driver,\n DriverLaunchOptions,\n MaskInstruction,\n RawInteractable,\n ScreencastFrame,\n ScreencastOptions,\n} from './driver-api.js';\nimport type { ParsedLocator, TextMatch } from '../spec/locators.js';\nimport type { TargetInfo, CursorWaypoint } from './events.js';\nimport type { Point } from '../shared/geometry.js';\nimport { minJerk } from '../shared/easing.js';\nimport { log } from '../shared/log.js';\n\n/** Budget for a single input dispatch (mouse/keyboard) — these have no Playwright timeout of\n * their own and a wedged renderer otherwise blocks them forever. */\nconst INPUT_TIMEOUT_MS = 5000;\n\nconst MASK_INIT_SCRIPT = `\n(() => {\n if (window.__playheadMaskInstalled) return;\n window.__playheadMaskInstalled = true;\n // Each masked element gets its own overlay box parented into that element's own DOM subtree.\n // This is what makes masking survive the top layer: an element inside a <dialog> modal (or a\n // popover) paints above a document-level overlay, so the box must be a descendant of the same\n // top-layer subtree to cover it. A position:fixed box stays out of flow, so parenting it into a\n // flex/grid container does not disturb layout.\n const boxes = new Map();\n const base = (box) => {\n box.setAttribute('aria-hidden', 'true');\n box.style.position = 'fixed';\n box.style.pointerEvents = 'none';\n box.style.zIndex = '2147483647';\n box.style.borderRadius = '5px';\n box.style.margin = '0';\n };\n const sync = (box, el, style) => {\n const r = el.getBoundingClientRect();\n const pad = 3; // cover focus rings / borders just outside the element box\n box.style.left = (r.left - pad) + 'px';\n box.style.top = (r.top - pad) + 'px';\n box.style.width = (r.width + pad * 2) + 'px';\n box.style.height = (r.height + pad * 2) + 'px';\n box.style.display = r.width > 0 && r.height > 0 ? 'block' : 'none';\n if (style === 'blur') {\n box.style.backdropFilter = 'blur(18px)';\n box.style.webkitBackdropFilter = 'blur(18px)';\n box.style.background = 'rgba(120,124,140,0.45)';\n } else {\n box.style.backdropFilter = '';\n box.style.background = '#2a2f3a';\n }\n };\n // In-page rule matching: CSS-expressible mask rules (testid=, css=) are pushed into\n // window.__playheadMaskCssRules and re-scanned continuously, so an element that APPEARS\n // MID-STEP (a token in a modal, an email in a toast, a row from the fetch settle waits on)\n // is tagged the frame it appears — not seconds later at the next step boundary. Node-side\n // tagging remains the backstop for rules needing Playwright semantics (role/label/text).\n let scanTick = 0;\n const scanRules = () => {\n const rules = window.__playheadMaskCssRules || [];\n for (const r of rules) {\n try {\n for (const el of document.querySelectorAll(r.css)) {\n if (!el.hasAttribute('data-playhead-mask')) el.setAttribute('data-playhead-mask', r.style);\n }\n } catch (e) {}\n }\n };\n const tick = () => {\n try {\n if (scanTick++ % 3 === 0) scanRules(); // every ~3 frames — cheap, and a 1-frame leak beats a 1-step leak\n const tagged = new Set(document.querySelectorAll('[data-playhead-mask]'));\n for (const [el, box] of boxes) {\n if (!tagged.has(el) || !el.isConnected) { box.remove(); boxes.delete(el); }\n }\n for (const el of tagged) {\n const parent = el.parentElement || document.body;\n let box = boxes.get(el);\n if (!box) {\n box = document.createElement('div');\n base(box);\n parent.appendChild(box);\n boxes.set(el, box);\n } else if (box.parentElement !== parent) {\n parent.appendChild(box);\n }\n sync(box, el, el.getAttribute('data-playhead-mask'));\n }\n } catch (e) {}\n requestAnimationFrame(tick);\n };\n requestAnimationFrame(tick);\n})();\n`;\n\n/** In-page fallback accessible-name computation for when the CDP AX lookup fails. */\nconst FALLBACK_NAME_FN = `(el) => {\n const norm = (s) => (s || '').replace(/\\\\s+/g, ' ').trim();\n const label = el.getAttribute('aria-label');\n if (label) return norm(label);\n const labelledBy = el.getAttribute('aria-labelledby');\n if (labelledBy) {\n const parts = labelledBy.split(/\\\\s+/).map((id) => {\n const ref = document.getElementById(id);\n return ref ? ref.textContent : '';\n });\n const joined = norm(parts.join(' '));\n if (joined) return joined;\n }\n if (el.labels && el.labels.length) return norm(el.labels[0].textContent);\n if (el.alt) return norm(el.alt);\n const text = norm(el.textContent);\n if (text) return text.slice(0, 80);\n if (el.placeholder) return norm(el.placeholder);\n if (el.title) return norm(el.title);\n return null;\n}`;\n\n/** In-page: gather every interactable element with the fields needed to author a grounded locator. */\nconst COLLECT_INTERACTABLES_FN = `() => {\n const norm = (s) => (s || '').replace(/\\\\s+/g, ' ').trim();\n // Accessible text = visible text excluding aria-hidden / hidden subtrees, matching how the\n // ARIA name is computed (so a decorative icon inside a link doesn't leak into the name).\n const accText = (el) => {\n let t = '';\n const walk = (node) => {\n if (node.nodeType === 3) { t += node.textContent; return; }\n if (node.nodeType !== 1) return;\n if (node.getAttribute && (node.getAttribute('aria-hidden') === 'true' || node.hasAttribute('hidden'))) return;\n for (const c of node.childNodes) walk(c);\n };\n walk(el);\n return norm(t);\n };\n const IMPLICIT = { A: 'link', BUTTON: 'button', SELECT: 'combobox', TEXTAREA: 'textbox', SUMMARY: 'button' };\n const inputRole = (el) => {\n const t = (el.getAttribute('type') || 'text').toLowerCase();\n if (t === 'checkbox') return 'checkbox';\n if (t === 'radio') return 'radio';\n if (t === 'range') return 'slider';\n if (t === 'button' || t === 'submit' || t === 'reset') return 'button';\n if (t === 'search') return 'searchbox';\n return 'textbox';\n };\n const accName = (el) => {\n const al = el.getAttribute('aria-label'); if (al) return norm(al);\n const lb = el.getAttribute('aria-labelledby');\n if (lb) { const parts = lb.split(/\\\\s+/).map((id) => { const r = document.getElementById(id); return r ? r.textContent : ''; }); const j = norm(parts.join(' ')); if (j) return j; }\n if (el.labels && el.labels.length) return accText(el.labels[0]);\n if (el.alt) return norm(el.alt);\n // NEVER walk a <select>'s subtree: that concatenates every <option> into a monster\n // \"Choose option...grayrednavy…\" pseudo-name that no human would write as a locator.\n if (el.tagName === 'SELECT' || el.tagName === 'DATALIST') {\n const sel = el.selectedOptions && el.selectedOptions[0];\n return sel ? norm(sel.textContent) : null;\n }\n const txt = accText(el); if (txt) return txt.slice(0, 80);\n if (el.placeholder) return norm(el.placeholder);\n if (el.title) return norm(el.title);\n return null;\n };\n // Landmark region for catalog grouping: which part of the page the element lives in.\n const regionOf = (el) => {\n const lm = el.closest('[role=dialog], dialog, nav, [role=navigation], header, [role=banner], aside, [role=complementary], footer, [role=contentinfo], main, [role=main]');\n if (!lm) return 'page';\n const tag = lm.tagName.toLowerCase();\n const role = lm.getAttribute && lm.getAttribute('role');\n if (tag === 'dialog' || role === 'dialog') return 'dialog';\n if (tag === 'nav' || role === 'navigation') return 'nav';\n if (tag === 'header' || role === 'banner') return 'header';\n if (tag === 'aside' || role === 'complementary') return 'sidebar';\n if (tag === 'footer' || role === 'contentinfo') return 'footer';\n return 'main';\n };\n const sel = 'button, a[href], input, select, textarea, summary, [role=button], [role=link], [role=tab], [role=switch], [role=menuitem], [role=checkbox], [contenteditable=\"\"], [contenteditable=true], h1, h2, h3';\n const seen = new Set();\n const out = [];\n for (const el of document.querySelectorAll(sel)) {\n if (seen.has(el)) continue; seen.add(el);\n const r = el.getBoundingClientRect();\n const style = getComputedStyle(el);\n const visible = r.width > 1 && r.height > 1 && style.visibility !== 'hidden' && style.display !== 'none' &&\n r.bottom > 0 && r.top < innerHeight && r.right > 0 && r.left < innerWidth;\n const tag = el.tagName;\n const explicit = el.getAttribute('role');\n const role = explicit || IMPLICIT[tag] || (tag === 'INPUT' ? inputRole(el) : (tag[0] === 'H' && tag.length === 2 ? 'heading' : null));\n let label = null;\n if (el.labels && el.labels.length) label = norm(el.labels[0].textContent);\n const options = tag === 'SELECT' ? Array.from(el.options).map((o) => norm(o.textContent)) : undefined;\n out.push({\n tag, role,\n accessibleName: accName(el),\n label,\n placeholder: el.getAttribute && el.getAttribute('placeholder') ? norm(el.getAttribute('placeholder')) : null,\n testId: el.getAttribute && (el.getAttribute('data-testid') || el.getAttribute('data-test-id')) || null,\n text: accText(el).slice(0, 80) || null,\n bbox: { x: r.x, y: r.y, w: r.width, h: r.height },\n visible,\n inputType: tag === 'INPUT' ? (el.getAttribute('type') || 'text').toLowerCase() : (tag === 'SELECT' ? 'select' : null),\n region: regionOf(el),\n ...(options ? { options } : {}),\n });\n }\n return out;\n}`;\n\nexport class PlaywrightDriver implements Driver {\n private browser!: Browser;\n private context!: BrowserContext;\n private page!: Page;\n private cdp!: CDPSession;\n /** Dedicated CDP session for the capture loop so its screenshots never contend with the\n * executor's accessibility/geometry lookups on the main session (which could deadlock). */\n private captureCdp!: CDPSession;\n private cursor: Point = { x: 0, y: 0 };\n private navCallbacks: ((url: string, t: number) => void)[] = [];\n private captureActive = false;\n private captureLoop: Promise<void> | null = null;\n private captureOnFrame: ((f: ScreencastFrame) => void) | null = null;\n private captureOpts: ScreencastOptions | null = null;\n private inflightGrab: Promise<void> | null = null;\n private lastFrameNodeMs = 0;\n private clockOffset = 0;\n private tagCounter = 0;\n private typingMaskLoc: ParsedLocator | null = null;\n\n async launch(opts: DriverLaunchOptions): Promise<void> {\n const env = opts.environment;\n this.browser = await chromium.launch({ headless: opts.headless ?? true });\n this.context = await this.browser.newContext({\n viewport: { width: opts.viewport.w, height: opts.viewport.h },\n deviceScaleFactor: opts.dpr,\n colorScheme: env?.colorScheme ?? 'light',\n ...(env?.timezone ? { timezoneId: env.timezone } : {}),\n ...(env?.locale ? { locale: env.locale } : {}),\n ...(env?.reducedMotion ? { reducedMotion: 'reduce' as const } : {}),\n ...(opts.storageStatePath ? { storageState: opts.storageStatePath } : {}),\n });\n this.context.setDefaultTimeout(10_000);\n this.context.setDefaultNavigationTimeout(20_000);\n\n // Network interception: blocked third-party noise, canned responses, HAR replay.\n const net = opts.network;\n if (net?.har) await this.context.routeFromHAR(net.har, { notFound: 'fallback' });\n for (const glob of net?.block ?? []) {\n await this.context.route(glob, (route) => route.fulfill({ status: 204, body: '' }));\n }\n for (const stub of net?.stub ?? []) {\n await this.context.route(stub.url, (route) =>\n route.fulfill({\n status: stub.status ?? 200,\n body: stub.body ?? '',\n contentType: stub.contentType ?? 'application/json',\n }),\n );\n }\n\n this.page = await this.context.newPage();\n if (env?.fixedTime) await this.page.clock.setFixedTime(new Date(env.fixedTime));\n await this.page.addInitScript(MASK_INIT_SCRIPT);\n this.cdp = await this.context.newCDPSession(this.page);\n this.captureCdp = await this.context.newCDPSession(this.page);\n this.page.on('framenavigated', (frame) => {\n if (frame === this.page.mainFrame()) {\n const t = Date.now();\n for (const cb of this.navCallbacks) cb(frame.url(), t);\n }\n });\n\n // Evidence + correctness listeners.\n this.page.on('console', (msg) => this.pushConsole(msg.type(), msg.text()));\n this.page.on('pageerror', (err) => this.pushConsole('pageerror', err.message));\n this.page.on('crash', () => this.pushConsole('crash', 'page crashed'));\n // Dialogs: Playwright's default DISMISSES, so a confirm()-guarded delete silently films the\n // cancel branch. Accept by default (spec-controllable), and always record it.\n const dialogPolicy = opts.dialogs ?? 'accept';\n this.page.on('dialog', (dialog) => {\n this.pushConsole('dialog', `${dialog.type()}(\"${dialog.message()}\") → ${dialogPolicy}`);\n void (dialogPolicy === 'accept' ? dialog.accept() : dialog.dismiss()).catch(() => {});\n });\n // Popups/new tabs: capture stays on the main page — record loudly instead of failing silently.\n this.context.on('page', (p) => {\n if (p !== this.page) {\n this.pushConsole('popup', `new tab/popup opened: ${p.url()} (not filmed — capture follows the main page)`);\n log.warn(`popup opened (${p.url()}) — multi-tab capture is not yet supported; footage stays on the main page`);\n }\n });\n\n this.cursor = { x: opts.viewport.w / 2, y: opts.viewport.h * 0.6 };\n await this.page.mouse.move(this.cursor.x, this.cursor.y);\n }\n\n private consoleBuf: { t: number; type: string; text: string }[] = [];\n\n private pushConsole(type: string, text: string): void {\n this.consoleBuf.push({ t: Date.now(), type, text: text.slice(0, 500) });\n if (this.consoleBuf.length > 500) this.consoleBuf.shift();\n }\n\n consoleLog(): { t: number; type: string; text: string }[] {\n return [...this.consoleBuf];\n }\n\n async close(): Promise<void> {\n if (!this.browser) return;\n await withTimeout(this.browser.close(), 8000).catch(() => {});\n }\n\n async measureClockOffset(): Promise<number> {\n const samples: number[] = [];\n for (let i = 0; i < 5; i++) {\n const t0 = Date.now();\n const browserNow = await withTimeout(this.page.evaluate(() => Date.now()), 2000).catch(() => t0);\n const t1 = Date.now();\n samples.push(browserNow - (t0 + t1) / 2);\n }\n samples.sort((a, b) => a - b);\n this.clockOffset = samples[2]!;\n return this.clockOffset;\n }\n\n async goto(url: string): Promise<void> {\n await this.page.goto(url, { waitUntil: 'load' });\n // fonts.ready can stay pending FOREVER on a wedged dev server (one stalled font asset never\n // resolves the promise — .catch() only covers rejection). Race it in-page against a short\n // timer, and bound the evaluate itself so a blocked main thread can't hang the capture.\n await withTimeout(\n this.page.evaluate(\n () => Promise.race([(document as any).fonts?.ready, new Promise((r) => setTimeout(r, 2000))]),\n ),\n 3000,\n ).catch(() => {});\n }\n\n onNavigation(cb: (url: string, t: number) => void): void {\n this.navCallbacks.push(cb);\n }\n\n currentUrl(): string {\n return this.page.url();\n }\n\n async currentTitle(): Promise<string> {\n return this.page.title().catch(() => '');\n }\n\n async ariaSnapshot(): Promise<string> {\n return this.page.locator('body').ariaSnapshot().catch(() => '');\n }\n\n async countMatches(loc: ParsedLocator): Promise<number> {\n try {\n return await this.toLocator(loc).count();\n } catch {\n return 0;\n }\n }\n\n async collectInteractables(): Promise<RawInteractable[]> {\n const collect = new Function(`return (${COLLECT_INTERACTABLES_FN})()`) as () => RawInteractable[];\n const out = await withTimeout(this.page.evaluate(collect), 10_000).catch(() => [] as RawInteractable[]);\n\n // Pierce one level of iframes that have an addressable selector, so exploration SEES frame\n // content (a Storybook canvas, an embedded widget) and emits frame-qualified locators.\n const handles = await this.page.$$('iframe').catch(() => []);\n for (const h of handles) {\n try {\n const sel = await h.evaluate((el: HTMLIFrameElement) => {\n if (el.id) return `#${CSS.escape(el.id)}`;\n const name = el.getAttribute('name');\n if (name) return `iframe[name=\"${name}\"]`;\n const tid = el.getAttribute('data-testid');\n if (tid) return `iframe[data-testid=\"${tid}\"]`;\n return null;\n });\n if (!sel) continue;\n const frame = await h.contentFrame();\n if (!frame) continue;\n const rect = await h.boundingBox();\n const inner = await withTimeout(\n frame.evaluate(collect),\n 8000,\n ).catch(() => [] as RawInteractable[]);\n for (const e of inner) {\n out.push({\n ...e,\n framePrefix: `frame=${sel}`,\n bbox: rect ? { x: e.bbox.x + rect.x, y: e.bbox.y + rect.y, w: e.bbox.w, h: e.bbox.h } : e.bbox,\n });\n }\n } catch {\n /* cross-origin or detached frame — unexplorable, skip */\n }\n }\n return out;\n }\n\n // ---------- locating & measuring ----------\n\n private toLocator(loc: ParsedLocator): Locator {\n // Frame chain first: `frame=#preview >> role=...` pierces into the iframe(s). Page-level\n // locators pierce shadow DOM for free but NEVER iframes — this is what makes an app whose\n // content lives in a frame (Storybook canvases, embedded checkouts, MFEs) addressable.\n let scope: Page | FrameLocator = this.page;\n for (const sel of loc.frames ?? []) scope = scope.frameLocator(sel);\n const b = loc.base;\n let l: Locator;\n switch (b.kind) {\n case 'role':\n l = scope.getByRole(b.role as Parameters<Page['getByRole']>[0], b.name ? { name: toPw(b.name), exact: isExact(b.name) } : {});\n break;\n case 'label':\n l = scope.getByLabel(toPw(b.match), { exact: isExact(b.match) });\n break;\n case 'text':\n l = scope.getByText(toPw(b.match), { exact: isExact(b.match) });\n break;\n case 'placeholder':\n l = scope.getByPlaceholder(toPw(b.match), { exact: isExact(b.match) });\n break;\n case 'testid':\n l = scope.getByTestId(b.value);\n break;\n case 'css':\n l = scope.locator(b.selector);\n break;\n }\n if (loc.nth !== undefined) l = l.nth(loc.nth);\n return l;\n }\n\n async resolveTarget(loc: ParsedLocator, timeoutMs: number): Promise<TargetInfo> {\n const locator = this.toLocator(loc);\n try {\n await locator.waitFor({ state: 'visible', timeout: timeoutMs });\n } catch (e) {\n // Never collapse distinct failures into one string: an ambiguous locator (strict-mode\n // violation), a hidden-but-present element, and a genuinely missing element each need a\n // different fix from the author — say which one this is.\n const msg = (e as Error).message ?? '';\n if (/strict mode violation/i.test(msg)) {\n const count = await locator.count().catch(() => -1);\n throw new Error(\n `Locator is ambiguous: ${loc.raw} matches ${count >= 0 ? count : 'multiple'} elements — add '>> nth=N' to pick one`,\n );\n }\n const count = await this.countMatches(loc);\n const reason =\n count === 0\n ? 'no matching element on the page'\n : `${count} match(es) present but none became visible`;\n throw new Error(\n `Target not resolvable: ${loc.raw} — ${reason} within ${timeoutMs}ms on ${this.page.url()} (${firstLine(msg)})`,\n );\n }\n await locator.scrollIntoViewIfNeeded().catch(() => {});\n // Layout stability: two identical geometry samples one frame apart.\n const deadline = Date.now() + timeoutMs;\n let prev: string | null = null;\n while (Date.now() < deadline) {\n const box = await locator.boundingBox();\n const sig = box ? `${box.x},${box.y},${box.width},${box.height}` : null;\n if (sig && sig === prev) break;\n prev = sig;\n await this.nextFrame();\n }\n const info = await this.measure(locator, loc);\n if (!info) throw new Error(`Target disappeared while measuring: ${loc.raw}`);\n return info;\n }\n\n /** Wait for the page to paint one frame, bounded — a concurrent screenshot must never let this hang. */\n private async nextFrame(): Promise<void> {\n await withTimeout(\n this.page.evaluate(() => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)))),\n 1500,\n ).catch(() => {});\n }\n\n async tryMeasure(loc: ParsedLocator): Promise<TargetInfo | null> {\n const locator = this.toLocator(loc);\n try {\n if (!(await locator.isVisible())) return null;\n return await this.measure(locator, loc);\n } catch {\n return null;\n }\n }\n\n private async measure(locator: Locator, loc: ParsedLocator): Promise<TargetInfo | null> {\n const tag = `ph-${++this.tagCounter}`;\n const geom = await locator\n .evaluate((el, t) => {\n el.setAttribute('data-playhead-t', t);\n const r = el.getBoundingClientRect();\n return {\n bbox: { x: r.x, y: r.y, w: r.width, h: r.height },\n scroll: { x: window.scrollX, y: window.scrollY },\n };\n }, tag)\n .catch(() => null);\n if (!geom) return null;\n // Frame-scoped elements: getBoundingClientRect is relative to the FRAME's viewport, but\n // every consumer (camera, verification pixel sampling, click coordinates) works in MAIN\n // viewport space. locator.boundingBox() is main-frame-relative — use it for position.\n if (loc.frames && loc.frames.length > 0) {\n const box = await withTimeout(locator.boundingBox(), 3000).catch(() => null);\n if (box) geom.bbox = { x: box.x, y: box.y, w: box.width, h: box.height };\n }\n\n let role: string | null = null;\n let name: string | null = null;\n try {\n const evalRes = (await withTimeout(\n this.cdp.send('Runtime.evaluate', {\n expression: `document.querySelector('[data-playhead-t=\"${tag}\"]')`,\n }),\n 4000,\n )) as { result: { objectId?: string } };\n if (evalRes.result.objectId) {\n const desc = (await withTimeout(\n this.cdp.send('DOM.describeNode', { objectId: evalRes.result.objectId }),\n 4000,\n )) as { node: { backendNodeId: number } };\n const ax = (await withTimeout(\n this.cdp.send('Accessibility.getPartialAXTree', {\n backendNodeId: desc.node.backendNodeId,\n fetchRelatives: false,\n }),\n 4000,\n )) as { nodes: { role?: { value?: string }; name?: { value?: string }; ignored?: boolean }[] };\n const node = ax.nodes?.[0];\n if (node && !node.ignored) {\n role = node.role?.value ?? null;\n name = node.name?.value ?? null;\n }\n await this.cdp.send('Runtime.releaseObject', { objectId: evalRes.result.objectId }).catch(() => {});\n }\n } catch (e) {\n log.debug(`AX lookup failed for ${loc.raw}: ${(e as Error).message}`);\n }\n if (!name) {\n name = await locator.evaluate(new Function('el', `return (${FALLBACK_NAME_FN})(el)`) as (el: Element) => string | null).catch(() => null);\n }\n await locator.evaluate((el) => el.removeAttribute('data-playhead-t')).catch(() => {});\n return { role, accessibleName: name, bbox: geom.bbox, scroll: geom.scroll };\n }\n\n // ---------- input ----------\n\n cursorPos(): Point {\n return { ...this.cursor };\n }\n\n async moveCursor(to: Point, durationMs: number): Promise<CursorWaypoint[]> {\n const from = { ...this.cursor };\n const waypoints: CursorWaypoint[] = [{ x: from.x, y: from.y, t: Date.now() }];\n const stepMs = 12;\n const steps = Math.max(2, Math.round(durationMs / stepMs));\n for (let i = 1; i <= steps; i++) {\n const p = minJerk(i / steps);\n const x = from.x + (to.x - from.x) * p;\n const y = from.y + (to.y - from.y) * p;\n // Input dispatch has no Playwright timeout and a wedged renderer can block it forever.\n await withTimeout(this.page.mouse.move(x, y), INPUT_TIMEOUT_MS);\n waypoints.push({ x, y, t: Date.now() });\n if (i < steps) await sleep(stepMs);\n }\n this.cursor = { ...to };\n return waypoints;\n }\n\n async clickAt(p: Point, opts?: { double?: boolean }): Promise<{ tDown: number; tUp: number }> {\n await withTimeout(this.page.mouse.move(p.x, p.y), INPUT_TIMEOUT_MS);\n this.cursor = { ...p };\n const tDown = Date.now();\n await withTimeout(this.page.mouse.down(), INPUT_TIMEOUT_MS);\n await sleep(70);\n await withTimeout(this.page.mouse.up(), INPUT_TIMEOUT_MS);\n if (opts?.double) {\n await sleep(60);\n await withTimeout(this.page.mouse.down({ clickCount: 2 }), INPUT_TIMEOUT_MS);\n await sleep(60);\n await withTimeout(this.page.mouse.up({ clickCount: 2 }), INPUT_TIMEOUT_MS);\n }\n return { tDown, tUp: Date.now() };\n }\n\n async typeText(text: string, delayMs: number): Promise<{ tFirst: number; tLast: number }> {\n const tFirst = Date.now();\n // Budget scales with the text: the typing itself takes length × delay by design.\n await withTimeout(this.page.keyboard.type(text, { delay: delayMs }), 10_000 + text.length * delayMs * 2);\n return { tFirst, tLast: Date.now() };\n }\n\n async press(keys: string): Promise<{ tDown: number }> {\n const tDown = Date.now();\n await withTimeout(this.page.keyboard.press(keys), INPUT_TIMEOUT_MS);\n return { tDown };\n }\n\n /**\n * The REAL click: Playwright's locator.click with actionability + hit-target verification and\n * retry. The cosmetic cursor has already animated to the target; this dispatches the action\n * through the checks a raw coordinate click bypasses (a toast/sticky header drifting under\n * the point between measure and click silently redirects a coordinate click).\n */\n async actClick(loc: ParsedLocator, opts?: { double?: boolean; timeoutMs?: number }): Promise<{ tDown: number; tUp: number }> {\n const locator = this.toLocator(loc);\n const tDown = Date.now();\n if (opts?.double) await locator.dblclick({ delay: 60, timeout: opts?.timeoutMs ?? 10_000 });\n else await locator.click({ delay: 70, timeout: opts?.timeoutMs ?? 10_000 });\n return { tDown, tUp: Date.now() };\n }\n\n async selectOption(loc: ParsedLocator, value: string): Promise<void> {\n const locator = this.toLocator(loc);\n try {\n await locator.selectOption({ label: value });\n } catch {\n await locator.selectOption(value);\n }\n // Leave the page CLEAN: dismiss any native popup the interaction opened and drop focus, so\n // the next step's locators aren't fighting a lingering dropdown or :focus-visible state.\n await withTimeout(this.page.keyboard.press('Escape'), INPUT_TIMEOUT_MS).catch(() => {});\n await withTimeout(\n locator.evaluate((el) => (el as HTMLElement).blur?.()),\n 2000,\n ).catch(() => {});\n }\n\n async scrollIntoView(loc: ParsedLocator): Promise<void> {\n const locator = this.toLocator(loc);\n await withTimeout(\n locator.evaluate((el) => el.scrollIntoView({ behavior: 'smooth', block: 'center' })),\n 5000,\n );\n }\n\n async scrollBy(by: { x: number; y: number }): Promise<void> {\n await withTimeout(\n this.page.evaluate(({ x, y }) => window.scrollBy({ left: x, top: y, behavior: 'smooth' }), by),\n 5000,\n );\n }\n\n async waitForScrollSettle(timeoutMs: number): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n let prev = Number.NaN;\n let stable = 0;\n while (Date.now() < deadline) {\n // Bound the evaluate itself: the outer deadline is only consulted between iterations, so a\n // single evaluate blocked by a busy main thread would otherwise blow straight past it.\n const y = await withTimeout(this.page.evaluate(() => window.scrollY), 1500).catch(() => prev);\n if (y === prev) {\n if (++stable >= 2) return;\n } else {\n stable = 0;\n prev = y;\n }\n await sleep(60);\n }\n }\n\n async expectState(\n loc: ParsedLocator,\n opts: { visible?: boolean; text?: string; count?: number },\n timeoutMs: number,\n ): Promise<void> {\n const locator = this.toLocator(loc);\n const deadline = Date.now() + timeoutMs;\n let lastErr = 'condition not met';\n while (Date.now() < deadline) {\n try {\n if (opts.count !== undefined) {\n const n = await locator.count();\n if (n === opts.count) return;\n lastErr = `expected ${opts.count} match(es), found ${n}`;\n await sleep(100);\n continue;\n }\n const visible = await locator.first().isVisible();\n if (opts.visible !== undefined && visible !== opts.visible) {\n lastErr = `expected visible=${opts.visible}, got ${visible}`;\n } else if (opts.text !== undefined) {\n const content = visible ? await locator.first().innerText() : '';\n if (!content.includes(opts.text)) {\n lastErr = `expected text to include \"${opts.text}\"`;\n } else {\n return;\n }\n } else {\n return;\n }\n } catch (e) {\n lastErr = (e as Error).message;\n }\n await sleep(100);\n }\n throw new Error(`expect failed for ${loc.raw}: ${lastErr}`);\n }\n\n // ---------- settling ----------\n\n /** Open requests → their start time. Long-lived streams (HMR sockets, SSE, long-polls) stop\n * counting after LONG_REQUEST_MS so a dev server can't pin the settle at its cap forever. */\n private pending = new Map<unknown, number>();\n private lastNetActivity = 0;\n private netTrackingInstalled = false;\n\n private installNetTracking(): void {\n if (this.netTrackingInstalled) return;\n this.netTrackingInstalled = true;\n this.lastNetActivity = Date.now();\n const IGNORED_TYPES = new Set(['eventsource', 'websocket', 'ping']);\n this.page.on('request', (req) => {\n if (IGNORED_TYPES.has(req.resourceType())) return;\n this.pending.set(req, Date.now());\n this.lastNetActivity = Date.now();\n });\n const done = (req: unknown) => {\n if (this.pending.delete(req)) this.lastNetActivity = Date.now();\n };\n this.page.on('requestfinished', done);\n this.page.on('requestfailed', done);\n }\n\n private static readonly LONG_REQUEST_MS = 2000;\n\n async settle(opts: { idleMs: number; capMs: number }): Promise<void> {\n this.installNetTracking();\n const start = Date.now();\n // Network idle — counting only requests younger than LONG_REQUEST_MS, so persistent\n // streams don't hold the gate.\n let capped = true;\n while (Date.now() - start < opts.capMs) {\n const now = Date.now();\n let inflight = 0;\n for (const t of this.pending.values()) {\n if (now - t < PlaywrightDriver.LONG_REQUEST_MS) inflight += 1;\n }\n if (inflight === 0 && now - this.lastNetActivity >= opts.idleMs) {\n capped = false;\n break;\n }\n await sleep(30);\n }\n if (capped) log.debug(`settle hit its ${opts.capMs}ms cap — footage may include in-flight loading`);\n // Real quiescence: no DOM mutations for 250ms AND no running finite animations (infinite\n // spinners are excluded — they'd block forever and their looping is the state, not a\n // transition). Bounded: a busy page costs at most ~1.8s here.\n await withTimeout(\n this.page.evaluate(\n () =>\n new Promise<void>((resolve) => {\n const done = () => {\n obs.disconnect();\n resolve();\n };\n let timer: ReturnType<typeof setTimeout>;\n const arm = () => {\n clearTimeout(timer);\n timer = setTimeout(() => {\n const running = (document.getAnimations?.() ?? []).filter((a) => {\n const t = a.effect?.getTiming?.();\n return a.playState === 'running' && t && t.iterations !== Infinity;\n });\n if (running.length === 0) done();\n else arm();\n }, 250);\n };\n const obs = new MutationObserver(() => arm());\n obs.observe(document.documentElement, { subtree: true, childList: true, attributes: true, characterData: true });\n arm();\n setTimeout(done, 1500); // hard floor: never block longer than this\n }),\n ),\n 1800,\n ).catch(() => {});\n // Final paint flush.\n await this.nextFrame();\n }\n\n async saveStorageState(path: string): Promise<void> {\n await this.context.storageState({ path });\n }\n\n // ---------- masking ----------\n\n /**\n * Install CSS-expressible mask rules for continuous in-page tagging (see MASK_INIT_SCRIPT).\n * Rules that can't be expressed as CSS (role/label/text) return false and stay Node-tagged.\n */\n async installMaskRules(rules: MaskInstruction[]): Promise<void> {\n const cssRules = rules\n .map((r) => ({ css: maskRuleToCss(r.loc), style: r.style }))\n .filter((r): r is { css: string; style: 'solid' | 'blur' } => r.css !== null);\n if (cssRules.length === 0) return;\n const payload = JSON.stringify(cssRules);\n // Init script → future documents (navigations); evaluate → the current one.\n await this.page.addInitScript(`window.__playheadMaskCssRules = ${payload};`);\n await withTimeout(\n this.page.evaluate((json) => ((window as any).__playheadMaskCssRules = JSON.parse(json)), payload),\n 3000,\n ).catch(() => {});\n }\n\n async applyMasks(\n rules: MaskInstruction[],\n ): Promise<{ style: 'solid' | 'blur'; x: number; y: number; w: number; h: number }[]> {\n const tagged: { style: 'solid' | 'blur'; x: number; y: number; w: number; h: number }[] = [];\n for (const rule of rules) {\n const locator = this.toLocator(rule.loc);\n // .all() (not a single-match locator) so rules matching many elements — e.g. every API-key\n // cell — are each tagged and measured, without tripping strict-mode.\n const all = await locator.all().catch(() => [] as Locator[]);\n for (const el of all) {\n const box = await el\n .evaluate((node, style) => {\n node.setAttribute('data-playhead-mask', style);\n const r = (node as HTMLElement).getBoundingClientRect();\n return { x: r.x, y: r.y, w: r.width, h: r.height };\n }, rule.style)\n .catch(() => null);\n if (box && box.w > 0 && box.h > 0) tagged.push({ style: rule.style, ...box });\n }\n }\n return tagged;\n }\n\n async setTypingMask(loc: ParsedLocator | null): Promise<void> {\n if (loc) {\n this.typingMaskLoc = loc;\n const locator = this.toLocator(loc);\n await locator.evaluate((el) => el.setAttribute('data-playhead-mask', 'solid')).catch(() => {});\n } else if (this.typingMaskLoc) {\n const locator = this.toLocator(this.typingMaskLoc);\n await locator.evaluate((el) => el.removeAttribute('data-playhead-mask')).catch(() => {});\n this.typingMaskLoc = null;\n }\n }\n\n // ---------- frame capture ----------\n //\n // Headless Chromium's CDP screencast is hard-locked to CSS-pixel resolution and ignores\n // deviceScaleFactor, so a paced Page.captureScreenshot loop with clip.scale is what actually\n // yields 2x frames (the zoom headroom the camera planner needs).\n\n async startCapture(onFrame: (f: ScreencastFrame) => void, opts: ScreencastOptions): Promise<void> {\n this.captureOnFrame = onFrame;\n this.captureOpts = opts;\n this.captureActive = true;\n const intervalMs = 1000 / opts.fps;\n this.captureLoop = (async () => {\n while (this.captureActive) {\n const started = Date.now();\n await this.grabFrame();\n const elapsed = Date.now() - started;\n if (elapsed < intervalMs) await sleep(intervalMs - elapsed);\n }\n })();\n }\n\n /** Grab a frame, coalescing on any in-flight grab (so callers can await the current one). */\n private grabFrame(): Promise<void> {\n if (this.inflightGrab) return this.inflightGrab;\n this.inflightGrab = this.doGrab().finally(() => {\n this.inflightGrab = null;\n });\n return this.inflightGrab;\n }\n\n private grabFailures = 0;\n\n private async doGrab(): Promise<void> {\n if (!this.captureOpts || !this.captureOnFrame) return;\n try {\n const opts = this.captureOpts;\n const vp = this.page.viewportSize() ?? { width: 1280, height: 720 };\n // The screenshot clip is in PAGE coordinates, so it must track the current scroll offset;\n // a fixed {0,0} clip captures document-top (scrolled out of view) as blank once the page\n // scrolls. Clipping to [scrollX, scrollY, vp] captures exactly the visible viewport, which\n // is also the space the event bounding boxes live in. Read the offset via getLayoutMetrics\n // (a native CDP call) rather than page JS, so it never contends with the page thread and\n // stall the capture loop during navigation.\n const scroll = await this.readScroll();\n // 1.5s budget: a stall costs one frame, not eighty. (Was 4s — during navigations that\n // produced measured 4-second frame voids at exactly the action beat.)\n const shot = (await withTimeout(\n this.captureCdp.send('Page.captureScreenshot', {\n format: opts.format,\n quality: opts.quality,\n clip: { x: scroll.x, y: scroll.y, width: vp.width, height: vp.height, scale: opts.scale },\n captureBeyondViewport: false,\n }),\n 1500,\n )) as { data: string };\n const tNodeMs = Date.now();\n this.lastFrameNodeMs = tNodeMs;\n this.grabFailures = 0;\n this.captureOnFrame({ data: Buffer.from(shot.data, 'base64'), tNodeMs });\n } catch {\n // withTimeout abandons but cannot cancel the CDP send, and Chromium serves a session's\n // sends IN ORDER — so a wedged screenshot head-of-line blocks every later grab on this\n // session. After consecutive failures, tear the session down and start a fresh one.\n this.grabFailures += 1;\n if (this.grabFailures >= 2) {\n try {\n await this.captureCdp.detach().catch(() => {});\n this.captureCdp = await this.context.newCDPSession(this.page);\n log.warn('capture: recreated CDP session after stalled screenshots');\n this.grabFailures = 0;\n } catch {\n /* context mid-navigation — next grab retries */\n }\n }\n }\n }\n\n private async readScroll(): Promise<{ x: number; y: number }> {\n try {\n const m = (await withTimeout(this.captureCdp.send('Page.getLayoutMetrics'), 1500)) as {\n cssVisualViewport?: { pageX?: number; pageY?: number };\n visualViewport?: { pageX?: number; pageY?: number };\n };\n const vv = m.cssVisualViewport ?? m.visualViewport;\n return { x: Math.round(vv?.pageX ?? 0), y: Math.round(vv?.pageY ?? 0) };\n } catch {\n return { x: 0, y: 0 };\n }\n }\n\n async stopCapture(): Promise<void> {\n this.captureActive = false;\n await this.captureLoop?.catch(() => {});\n this.captureLoop = null;\n }\n\n lastFrameAt(): number {\n return this.lastFrameNodeMs;\n }\n\n async captureNow(): Promise<void> {\n // Wait out any in-flight grab (it may predate the action), then force a guaranteed fresh one\n // that reflects the settled post-action state. Never gives up early under load.\n if (this.inflightGrab) await this.inflightGrab.catch(() => {});\n await this.grabFrame();\n }\n}\n\nfunction toPw(m: TextMatch): string | RegExp {\n if ('exact' in m) return m.exact;\n if ('substring' in m) return m.substring;\n return new RegExp(m.regex.source, m.regex.flags);\n}\n\nfunction isExact(m: TextMatch): boolean {\n return 'exact' in m;\n}\n\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\n/** CSS selector for a mask rule when the locator engine is CSS-expressible; null otherwise. */\nfunction maskRuleToCss(loc: ParsedLocator): string | null {\n const b = loc.base;\n if (b.kind === 'css') return b.selector;\n if (b.kind === 'testid') return `[data-testid=${JSON.stringify(b.value)}]`;\n return null;\n}\n\nfunction firstLine(s: string): string {\n const line = s.split('\\n')[0] ?? '';\n return line.length > 160 ? `${line.slice(0, 159)}…` : line;\n}\n\n/** Reject if a promise (typically a CDP send) doesn't settle in time, so a stalled call can't freeze the pipeline. */\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`operation timed out after ${ms}ms`)), ms);\n p.then(\n (v) => {\n clearTimeout(timer);\n resolve(v);\n },\n (e) => {\n clearTimeout(timer);\n reject(e);\n },\n );\n });\n}\n","/** Cubic bezier easing (CSS-style: fixed endpoints (0,0) and (1,1)). Serializable by its four control values. */\nexport type BezierParams = [number, number, number, number];\n\nexport const EASE_ZOOM: BezierParams = [0.4, 0, 0.2, 1];\nexport const EASE_PAN: BezierParams = [0.3, 0, 0.15, 1];\n\n/** Evaluate a CSS cubic-bezier at progress t ∈ [0,1] (solves x(t)=t for the parameter, returns y). */\nexport function cubicBezier(p: BezierParams, t: number): number {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n const [x1, y1, x2, y2] = p;\n // Newton-Raphson on x(u) = t\n let u = t;\n for (let i = 0; i < 8; i++) {\n const x = bez(u, x1, x2) - t;\n if (Math.abs(x) < 1e-6) break;\n const dx = dbez(u, x1, x2);\n if (Math.abs(dx) < 1e-6) break;\n u -= x / dx;\n }\n return bez(Math.max(0, Math.min(1, u)), y1, y2);\n}\n\nfunction bez(u: number, a: number, b: number): number {\n const v = 1 - u;\n return 3 * v * v * u * a + 3 * v * u * u * b + u * u * u;\n}\n\nfunction dbez(u: number, a: number, b: number): number {\n const v = 1 - u;\n return 3 * v * v * a + 6 * v * u * (b - a) + 3 * u * u * (1 - b);\n}\n\n/** Minimum-jerk position profile: smooth human-like travel, s(0)=0, s(1)=1, zero velocity/acceleration at ends. */\nexport function minJerk(t: number): number {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n return t * t * t * (10 - 15 * t + 6 * t * t);\n}\n","import pc from 'picocolors';\n\nlet verbose = false;\n\nexport function setVerbose(v: boolean): void {\n verbose = v;\n}\n\n// ALL human logging goes to stderr: stdout belongs to machine output (--json, catalogs),\n// so `playhead render --json | jq` works without ANSI noise corrupting the payload.\nexport const log = {\n info(msg: string): void {\n console.error(pc.dim('[playhead]') + ' ' + msg);\n },\n step(msg: string): void {\n console.error(pc.cyan(' ▸ ') + msg);\n },\n ok(msg: string): void {\n console.error(pc.green(' ✓ ') + msg);\n },\n warn(msg: string): void {\n console.error(pc.yellow(' ⚠ ') + msg);\n },\n error(msg: string): void {\n console.error(pc.red(' ✗ ') + msg);\n },\n debug(msg: string): void {\n if (verbose) console.error(pc.dim(' · ' + msg));\n },\n};\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport sharp from 'sharp';\nimport type { Spec } from '../spec/schema.js';\nimport type { EventLog } from '../capture/events.js';\nimport type { BundleManifest, FrameIndexEntry, MaskSample } from './types.js';\nimport { sha256Json } from './hash.js';\nimport { PLAYHEAD_VERSION } from '../shared/version.js';\n\n\nexport class BundleWriter {\n private frames: FrameIndexEntry[] = [];\n private pendingWrites: Promise<unknown>[] = [];\n private maskSamples: MaskSample[] = [];\n private counter = 0;\n private ready: Promise<void>;\n\n constructor(\n private readonly dir: string,\n private readonly captureFormat: 'jpeg' | 'png',\n ) {\n this.ready = mkdir(join(dir, 'frames'), { recursive: true }).then(() => {});\n }\n\n /** Queue a frame write. `t` is capture-relative ms. */\n addFrame(data: Buffer, t: number): void {\n this.counter += 1;\n const name = `${String(this.counter).padStart(6, '0')}.${this.captureFormat === 'jpeg' ? 'jpg' : 'png'}`;\n this.frames.push({ f: name, t: round1(t) });\n this.pendingWrites.push(\n this.ready.then(() => writeFile(join(this.dir, 'frames', name), data)),\n );\n }\n\n addMaskSample(sample: MaskSample): void {\n this.maskSamples.push(sample);\n }\n\n frameCount(): number {\n return this.counter;\n }\n\n async finish(meta: {\n spec: Spec;\n events: EventLog;\n appUrl: string;\n viewport: { w: number; h: number };\n dpr: number;\n clockOffsetMs: number;\n durationMs: number;\n partial?: boolean;\n failure?: { stepRef: string; message: string };\n }): Promise<BundleManifest> {\n await this.ready;\n await Promise.all(this.pendingWrites);\n this.frames.sort((a, b) => a.t - b.t);\n\n // Actual frame pixel size is the source of truth for frame-space scale.\n let frameW = meta.viewport.w * meta.dpr;\n let frameH = meta.viewport.h * meta.dpr;\n const first = this.frames[0];\n if (first) {\n const info = await sharp(join(this.dir, 'frames', first.f)).metadata();\n if (info.width && info.height) {\n frameW = info.width;\n frameH = info.height;\n }\n }\n\n const manifest: BundleManifest = {\n schema: 'playhead/bundle@1',\n playheadVersion: PLAYHEAD_VERSION,\n specHash: sha256Json(meta.spec),\n appUrl: meta.appUrl,\n viewport: meta.viewport,\n dpr: meta.dpr,\n frameW,\n frameH,\n clockOffsetMs: meta.clockOffsetMs,\n frameCount: this.frames.length,\n durationMs: round1(meta.durationMs),\n createdAtIso: new Date().toISOString(),\n captureFormat: this.captureFormat,\n hashes: {\n events: sha256Json(meta.events),\n framesIndex: sha256Json(this.frames),\n },\n ...(meta.partial ? { partial: true } : {}),\n ...(meta.failure ? { failure: meta.failure } : {}),\n };\n\n await Promise.all([\n writeFile(join(this.dir, 'frames', 'index.json'), JSON.stringify(this.frames)),\n writeFile(join(this.dir, 'events.json'), JSON.stringify(meta.events, null, 2)),\n writeFile(join(this.dir, 'masks.json'), JSON.stringify(this.maskSamples, null, 2)),\n writeFile(join(this.dir, 'spec.resolved.json'), JSON.stringify(meta.spec, null, 2)),\n writeFile(join(this.dir, 'manifest.json'), JSON.stringify(manifest, null, 2)),\n ]);\n return manifest;\n }\n}\n\nfunction round1(n: number): number {\n return Math.round(n * 10) / 10;\n}\n","import { createHash } from 'node:crypto';\nimport { createReadStream } from 'node:fs';\n\nexport function sha256Json(value: unknown): string {\n return createHash('sha256').update(JSON.stringify(value)).digest('hex');\n}\n\nexport function sha256File(path: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash('sha256');\n createReadStream(path)\n .on('data', (d) => hash.update(d))\n .on('end', () => resolve(hash.digest('hex')))\n .on('error', reject);\n });\n}\n","import { createRequire } from 'node:module';\n\n/** The ONE version source: package.json. Bundle manifests, the CLI, the MCP server, and\n * verdict provenance all read this — they can never disagree with the installed package. */\nexport const PLAYHEAD_VERSION: string = (\n createRequire(import.meta.url)('../../package.json') as { version: string }\n).version;\n","/** Axis-aligned rectangle. Space is documented at each use site (viewport CSS px, frame px, or output px). */\nexport interface Rect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport function rectCenter(r: Rect): Point {\n return { x: r.x + r.w / 2, y: r.y + r.h / 2 };\n}\n\nexport function rectUnion(a: Rect, b: Rect): Rect {\n const x = Math.min(a.x, b.x);\n const y = Math.min(a.y, b.y);\n return {\n x,\n y,\n w: Math.max(a.x + a.w, b.x + b.w) - x,\n h: Math.max(a.y + a.h, b.y + b.h) - y,\n };\n}\n\nexport function padRect(r: Rect, pad: number): Rect {\n return { x: r.x - pad, y: r.y - pad, w: r.w + pad * 2, h: r.h + pad * 2 };\n}\n\n/** True when `inner` lies fully inside `outer`, with an optional margin inside `outer`. */\nexport function rectContains(outer: Rect, inner: Rect, margin = 0): boolean {\n return (\n inner.x >= outer.x + margin &&\n inner.y >= outer.y + margin &&\n inner.x + inner.w <= outer.x + outer.w - margin &&\n inner.y + inner.h <= outer.y + outer.h - margin\n );\n}\n\nexport function clamp(v: number, min: number, max: number): number {\n return v < min ? min : v > max ? max : v;\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function dist(a: Point, b: Point): number {\n return Math.hypot(a.x - b.x, a.y - b.y);\n}\n\n/**\n * Camera state on the source viewport plane. The visible window always has the\n * OUTPUT aspect ratio (width-anchored): zoom=1 shows the full viewport width,\n * with height vpW/zoom/outAspect — the camera pans vertically over pages taller\n * than 16:9 rather than distorting them.\n */\nexport interface CameraState {\n cx: number;\n cy: number;\n zoom: number;\n}\n\nexport interface CameraPlane {\n vpW: number;\n vpH: number;\n outW: number;\n outH: number;\n}\n\n/** The viewport-space rect visible at a camera state (output-aspect, width-anchored). */\nexport function visibleRect(cam: CameraState, plane: CameraPlane): Rect {\n const w = plane.vpW / cam.zoom;\n const h = (w * plane.outH) / plane.outW;\n return { x: cam.cx - w / 2, y: cam.cy - h / 2, w, h };\n}\n\n/** Minimum zoom that keeps the visible window inside a page of this height. */\nexport function minZoom(plane: CameraPlane): number {\n return Math.max(1, plane.vpW / ((plane.vpH * plane.outW) / plane.outH));\n}\n\n/** Clamp a camera so its visible rect stays inside the viewport. */\nexport function clampCamera(cam: CameraState, plane: CameraPlane): CameraState {\n const zoom = Math.max(cam.zoom, minZoom(plane));\n const w = plane.vpW / zoom;\n const h = (w * plane.outH) / plane.outW;\n return {\n zoom,\n cx: clamp(cam.cx, w / 2, plane.vpW - w / 2),\n cy: clamp(cam.cy, h / 2, plane.vpH - h / 2),\n };\n}\n\n/** Project a viewport-space rect into output space given a camera state. */\nexport function projectRect(r: Rect, cam: CameraState, plane: CameraPlane): Rect {\n const vis = visibleRect(cam, plane);\n const s = plane.outW / vis.w;\n return { x: (r.x - vis.x) * s, y: (r.y - vis.y) * s, w: r.w * s, h: r.h * s };\n}\n\n/** Project a viewport-space point into output space given a camera state. */\nexport function projectPoint(p: Point, cam: CameraState, plane: CameraPlane): Point {\n const vis = visibleRect(cam, plane);\n const s = plane.outW / vis.w;\n return { x: (p.x - vis.x) * s, y: (p.y - vis.y) * s };\n}\n","/**\n * Typed exit codes — a CI pipeline must be able to tell WHICH kind of red this is:\n *\n * 0 pass — rendered and publishable\n * 1 flow failure — the APP broke the flow (locator gone, expect failed, step timeout);\n * a partial bundle + failure clip exist\n * 2 quality fail — the flow ran but the video failed verification (framing, captions, audio)\n * 3 infra failure — environment problems (browser/ffmpeg missing, launch failed)\n * 4 usage error — bad spec / bad arguments\n *\n * A test tool that can't distinguish \"your app is broken\" from \"the video is ugly\" from\n * \"the runner is misconfigured\" gets `|| true`'d. This is the contract that prevents that.\n */\nexport const EXIT = {\n OK: 0,\n FLOW: 1,\n QUALITY: 2,\n INFRA: 3,\n USAGE: 4,\n} as const;\n\n/** The app broke the scripted flow (capture-time step failure). */\nexport class FlowError extends Error {\n readonly exitCode = EXIT.FLOW;\n}\n\n/** Environment/tooling problem — nothing about the app or the spec. */\nexport class InfraError extends Error {\n readonly exitCode = EXIT.INFRA;\n}\n\n/** Classify an arbitrary thrown error into an exit code. SpecErrors are matched by name to\n * avoid a circular import with the spec parser. */\nexport function exitCodeFor(e: unknown): number {\n if (e && typeof e === 'object') {\n if ('exitCode' in e && typeof (e as { exitCode: unknown }).exitCode === 'number') {\n return (e as { exitCode: number }).exitCode;\n }\n if ((e as Error).name === 'SpecError' || e instanceof Object && (e as Error).constructor?.name === 'SpecError') {\n return EXIT.USAGE;\n }\n }\n return EXIT.INFRA;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { BundleData, BundleManifest, FrameIndexEntry, MaskSample } from './types.js';\nimport type { EventLog } from '../capture/events.js';\n\nexport async function openBundle(dir: string): Promise<BundleData> {\n const [manifestRaw, eventsRaw, framesRaw, masksRaw] = await Promise.all([\n readFile(join(dir, 'manifest.json'), 'utf8'),\n readFile(join(dir, 'events.json'), 'utf8'),\n readFile(join(dir, 'frames', 'index.json'), 'utf8'),\n readFile(join(dir, 'masks.json'), 'utf8').catch(() => '[]'),\n ]);\n const manifest = JSON.parse(manifestRaw) as BundleManifest;\n if (manifest.schema !== 'playhead/bundle@1') {\n throw new Error(`Unsupported bundle schema \"${manifest.schema}\" in ${dir}`);\n }\n const events = JSON.parse(eventsRaw) as EventLog;\n const frames = JSON.parse(framesRaw) as FrameIndexEntry[];\n const maskSamples = JSON.parse(masksRaw) as MaskSample[];\n if (frames.length === 0) throw new Error(`Bundle ${dir} contains no frames`);\n return { dir, manifest, events, frames, maskSamples };\n}\n\n/** Index of the latest frame with t ≤ tMs (hold semantics); clamps to the first frame. */\nexport function frameIndexForTime(frames: FrameIndexEntry[], tMs: number): number {\n let lo = 0;\n let hi = frames.length - 1;\n if (tMs <= frames[0]!.t) return 0;\n if (tMs >= frames[hi]!.t) return hi;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (frames[mid]!.t <= tMs) lo = mid;\n else hi = mid - 1;\n }\n return lo;\n}\n\nexport function framePath(bundle: BundleData, index: number): string {\n return join(bundle.dir, 'frames', bundle.frames[index]!.f);\n}\n","import { join } from 'node:path';\nimport { writeFile } from 'node:fs/promises';\nimport type { BundleData } from '../bundle/types.js';\nimport type { Spec } from '../spec/schema.js';\nimport { resolveResolution } from '../spec/schema.js';\nimport { resolveTheme, type ResolvedTheme } from '../theme/index.js';\nimport type { ComposeDiagnostics, ComposeManifest, OutputProfile } from './types.js';\nimport { profileForAspect, withStage } from './types.js';\nimport { kindProfile } from './kinds.js';\nimport { buildTimeline, pacingConfig } from './timeline/pacing.js';\nimport { planCamera } from './camera/planner.js';\nimport { planCursor } from './cursor/path.js';\nimport { buildOverlays } from './overlays/build.js';\nimport { renderVideo } from './render/renderer.js';\nimport { registerFonts } from '../theme/index.js';\nimport { sha256File } from '../bundle/hash.js';\nimport { log } from '../shared/log.js';\nimport { actionEvents } from '../capture/events.js';\nimport { writeCaption, writeNarration, type StepTexts } from './captions.js';\nimport { flattenSteps } from '../spec/schema.js';\nimport { synthesizeNarration, type NarrationClip } from '../audio/tts.js';\nimport { mixAudio } from '../audio/mux.js';\n\nexport interface ComposeResult {\n videoPath: string;\n manifestPath: string;\n manifest: ComposeManifest;\n}\n\n/** Pure planning: bundle + spec + theme → compose manifest. No rendering. */\n/** Per-step caption/narration text from the LIVE spec, keyed by stepRef — so text edits are a\n * re-compose, never a re-capture. */\nexport function specStepTexts(spec: Spec): Map<string, StepTexts> {\n const map = new Map<string, StepTexts>();\n for (const a of flattenSteps(spec)) {\n const s = a.step;\n if (s.caption || s.narration) {\n map.set(`${a.sceneId}/${a.stepIndex}`, {\n ...(s.caption ? { caption: s.caption } : {}),\n ...(s.narration ? { narration: s.narration } : {}),\n });\n }\n }\n return map;\n}\n\nexport function plan(\n bundle: BundleData,\n spec: Spec,\n theme?: ResolvedTheme,\n profile?: OutputProfile,\n audioMs?: Map<string, number>,\n): ComposeManifest {\n registerFonts();\n const resolvedTheme = theme ?? resolveTheme(spec);\n const kind = kindProfile(spec.output.kind);\n let prof: OutputProfile =\n profile ?? profileForAspect(spec.output.aspect, resolveResolution(spec), spec.output.fps);\n // The stage (matte + card + browser chrome) is the produced look; bug-repro stays literal.\n if (kind.stage && !prof.stage) prof = withStage(prof, true);\n const diagnostics: ComposeDiagnostics = { overflows: [], cameraFallbacks: [], clockWarnings: [] };\n const cfg = pacingConfig(spec.output.pacing ?? kind.pacing, kind);\n // Long-form teaching dwell: stretch the min-step, per-action holds, and outro so\n // each screen lingers. Idle-gap trimming and title card stay fixed (they're not dwell).\n const dwell = spec.output.dwellScale;\n if (dwell && dwell !== 1) {\n cfg.minStepMs *= dwell;\n cfg.outroMs *= dwell;\n for (const k of Object.keys(cfg.holds) as (keyof typeof cfg.holds)[]) cfg.holds[k] *= dwell;\n }\n const timeline = buildTimeline(bundle.events, cfg, audioMs);\n\n // Closing card: a title-card-styled segment appended after the outro.\n const END_CARD_MS = 2400;\n if (spec.output.endCard) {\n const endStart = timeline.durationMs;\n timeline.segments.push({ kind: 'card', outStart: endStart, outEnd: endStart + END_CARD_MS, cardId: 'end' });\n timeline.durationMs += END_CARD_MS;\n }\n // FAILURE CLIP: a partial bundle (capture died mid-run) composes into a diagnosis — the\n // captured footage plays through, then holds on a red card naming the step and the error.\n // This is the artifact a red CI run hands the developer: watch what happened, not a stack line.\n const FAILURE_CARD_MS = 3200;\n if (bundle.manifest.partial && bundle.manifest.failure) {\n const failStart = timeline.durationMs;\n timeline.segments.push({ kind: 'card', outStart: failStart, outEnd: failStart + FAILURE_CARD_MS, cardId: 'failure' });\n timeline.durationMs += FAILURE_CARD_MS;\n }\n\n // Clock sanity: warn when the action beat has no frame within 150ms after it.\n for (const step of timeline.steps) {\n const hasFrame = bundle.frames.some((f) => f.t >= step.srcAction && f.t <= step.srcAction + 150);\n if (!hasFrame && step.kind !== 'wait' && step.kind !== 'expect') {\n diagnostics.clockWarnings.push(`${step.stepRef}: no source frame within 150ms after the action`);\n }\n }\n\n const camera = planCamera(timeline.steps, bundle.events, prof, timeline.durationMs, {\n emphasis: kind.cameraEmphasis,\n });\n diagnostics.cameraFallbacks.push(...camera.fallbacks);\n const cursor = planCursor(timeline.steps, bundle.events);\n\n // Cross-dissolve at scene boundaries: the old footage (held at its last frame) fades into the\n // new scene instead of a hard cut.\n const transitions: { tStart: number; tEnd: number; srcFrom: number }[] = [];\n for (let i = 1; i < timeline.steps.length; i++) {\n const prev = timeline.steps[i - 1]!;\n const cur = timeline.steps[i]!;\n if (cur.sceneId !== prev.sceneId) {\n const tStart = cur.outStart;\n transitions.push({ tStart, tEnd: tStart + 280, srcFrom: Math.max(0, prev.srcSettled - 1) });\n }\n }\n\n const subtitle = spec.subtitle ?? safeHost(bundle.manifest.appUrl);\n const sceneTitles = new Map(\n spec.scenes.filter((s) => s.title).map((s) => [s.id, s.title as string]),\n );\n const overlays = buildOverlays(\n timeline.steps,\n bundle.events,\n resolvedTheme,\n prof,\n spec.title,\n subtitle,\n cfg.titleCardMs,\n diagnostics,\n kind,\n sceneTitles,\n camera.keyframes,\n specStepTexts(spec),\n );\n if (spec.output.endCard && !bundle.manifest.partial) {\n const endStart = timeline.durationMs - END_CARD_MS;\n overlays.push({ kind: 'dip', tStart: endStart - 350, tEnd: endStart, direction: 'out' });\n overlays.push({\n kind: 'titleCard',\n cardId: 'end',\n title: spec.output.endCard.title,\n ...(spec.output.endCard.subtitle ? { subtitle: spec.output.endCard.subtitle } : {}),\n tStart: endStart,\n tEnd: timeline.durationMs,\n });\n }\n if (bundle.manifest.partial && bundle.manifest.failure) {\n const failStart = timeline.durationMs - FAILURE_CARD_MS;\n overlays.push({ kind: 'dip', tStart: failStart - 300, tEnd: failStart, direction: 'out' });\n overlays.push({\n kind: 'failureCard',\n stepRef: bundle.manifest.failure.stepRef,\n message: bundle.manifest.failure.message,\n tStart: failStart,\n tEnd: timeline.durationMs,\n });\n }\n\n const totalFrames = Math.ceil((timeline.durationMs / 1000) * prof.fps);\n return {\n schema: 'playhead/compose@1',\n profile: prof,\n viewport: bundle.manifest.viewport,\n durationMs: timeline.durationMs,\n totalFrames,\n segments: timeline.segments,\n camera: camera.keyframes,\n cursor: cursor.segments,\n ripples: cursor.ripples,\n overlays,\n ...(transitions.length > 0 ? { transitions } : {}),\n steps: timeline.steps,\n theme: resolvedTheme,\n diagnostics,\n bundleHashes: bundle.manifest.hashes,\n };\n}\n\nexport interface ComposeOptions {\n outDir: string;\n fileName?: string;\n theme?: ResolvedTheme;\n profile?: OutputProfile;\n}\n\n/** Full composition: plan + render + write manifest. Never touches the live app. */\nexport async function compose(bundle: BundleData, spec: Spec, opts: ComposeOptions): Promise<ComposeResult> {\n // Voice narration (optional): synthesize each step's spoken line first, so pacing\n // can grow every step to fit it. TTS is local (macOS `say`) and cached in the bundle.\n const audioCfg = spec.output.audio;\n let narration: Map<string, NarrationClip> | undefined;\n let audioMs: Map<string, number> | undefined;\n if (audioCfg && audioCfg.narration === 'tts') {\n const texts = specStepTexts(spec);\n const lines = actionEvents(bundle.events)\n .map((e) => {\n const ref = `${e.sceneId}/${e.stepIndex}`;\n return { stepRef: ref, text: writeNarration(e, texts.get(ref)) };\n })\n .filter((l): l is { stepRef: string; text: string } => typeof l.text === 'string' && l.text.length > 0);\n log.info(`synthesizing narration: ${lines.length} lines (${audioCfg.provider}, voice ${audioCfg.voice ?? 'Samantha'})`);\n try {\n narration = await synthesizeNarration(lines, audioCfg, join(opts.outDir, 'narration'));\n audioMs = new Map([...narration].map(([k, v]) => [k, v.durationMs]));\n } catch (e) {\n // A host without the TTS binary (e.g. Linux CI with provider `say`) must not kill the\n // render — degrade to a silent video LOUDLY. `playhead doctor --ci` reports this upfront.\n log.warn(`narration unavailable on this host (${(e as Error).message.split('\\n')[0]}) — rendering WITHOUT voice`);\n narration = undefined;\n audioMs = undefined;\n }\n }\n\n const manifest = plan(bundle, spec, opts.theme, opts.profile, audioMs);\n for (const w of manifest.diagnostics.clockWarnings) log.warn(w);\n for (const f of manifest.diagnostics.cameraFallbacks) log.warn(f);\n\n const videoPath = join(opts.outDir, opts.fileName ?? 'out.mp4');\n log.info(\n `composing ${(manifest.durationMs / 1000).toFixed(1)}s (${manifest.totalFrames} frames @ ${manifest.profile.fps}fps, ${manifest.profile.width}x${manifest.profile.height})`,\n );\n await renderVideo(bundle, manifest, videoPath);\n\n // Audio bed: narration + click SFX + (user-supplied) music, ducked and loudness-normalized.\n if (audioCfg && (narration || audioCfg.sfx || audioCfg.music)) {\n const clips = await mixAudio(videoPath, manifest.steps, manifest.durationMs, {\n ...(narration ? { narration } : {}),\n ...(audioCfg.sfx ? { sfxBeats: manifest.ripples } : {}),\n ...(audioCfg.music ? { music: audioCfg.music } : {}),\n cacheDir: join(opts.outDir, 'narration'),\n });\n if (narration) {\n manifest.audio = {\n narrated: true,\n provider: audioCfg.provider,\n voice: audioCfg.voice ?? 'Samantha',\n lines: clips.length,\n clips,\n };\n }\n log.info(\n `✓ audio: ${clips.length} narration line(s)` +\n `${audioCfg.sfx ? `, ${manifest.ripples.length} click(s)` : ''}` +\n `${audioCfg.music ? ', music bed' : ''} → ${videoPath}`,\n );\n }\n\n manifest.videoSha256 = await sha256File(videoPath);\n const manifestPath = join(opts.outDir, 'compose-manifest.json');\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2));\n return { videoPath, manifestPath, manifest };\n}\n\nexport async function renderFromManifest(bundle: BundleData, manifest: ComposeManifest, videoPath: string): Promise<void> {\n await renderVideo(bundle, manifest, videoPath);\n}\n\nfunction safeHost(url: string): string {\n try {\n return new URL(url).host;\n } catch {\n return url;\n }\n}\n","import { existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { createRequire } from 'node:module';\nimport { GlobalFonts } from '@napi-rs/canvas';\nimport type { Spec } from '../spec/schema.js';\n\nexport interface ResolvedTheme {\n name: string;\n /** Accent color for cursor ripple, badges, highlights. */\n accent: string;\n /** Title-card and letterbox background. */\n bg: string;\n bgSubtle: string;\n /** Caption card background (rgba string). */\n surface: string;\n onSurface: string;\n onSurfaceDim: string;\n fontFamily: string;\n captionFontPx: number;\n captionMinFontPx: number;\n captionMaxLines: number;\n captionPosition: 'bottom' | 'top' | 'off';\n radius: number;\n}\n\nconst DEFAULT_THEME: ResolvedTheme = {\n name: 'default',\n accent: '#5B8DEF',\n bg: '#12161f',\n bgSubtle: '#1a2029',\n surface: 'rgba(18, 22, 31, 0.92)',\n onSurface: '#ffffff',\n onSurfaceDim: 'rgba(255,255,255,0.72)',\n fontFamily: 'Inter',\n // Broadcast-subtitle scale: ~3.3% of a 1080p frame. At the old 26px the caption was the same\n // size as the app's upscaled body copy and read as part of the UI, not narration above it.\n captionFontPx: 36,\n captionMinFontPx: 28,\n captionMaxLines: 2,\n captionPosition: 'bottom',\n radius: 12,\n};\n\nexport function resolveTheme(spec: Spec): ResolvedTheme {\n return {\n ...DEFAULT_THEME,\n ...(spec.theme.accent ? { accent: spec.theme.accent } : {}),\n captionPosition: spec.theme.captions,\n };\n}\n\nlet fontsRegistered = false;\n\n/** Register bundled Inter faces so rendering is deterministic across machines. */\nexport function registerFonts(): void {\n if (fontsRegistered) return;\n fontsRegistered = true;\n const require = createRequire(import.meta.url);\n let pkgDir: string;\n try {\n pkgDir = dirname(require.resolve('@expo-google-fonts/inter/package.json'));\n } catch {\n throw new Error('Font package @expo-google-fonts/inter not found — run npm install');\n }\n const faces: [string, string][] = [\n ['400Regular/Inter_400Regular.ttf', 'Inter'],\n ['500Medium/Inter_500Medium.ttf', 'Inter Medium'],\n ['600SemiBold/Inter_600SemiBold.ttf', 'Inter SemiBold'],\n ['700Bold/Inter_700Bold.ttf', 'Inter Bold'],\n ];\n for (const [rel, family] of faces) {\n const p = join(pkgDir, rel);\n if (existsSync(p)) GlobalFonts.registerFromPath(p, family);\n }\n}\n","import type { Rect, Point, CameraState } from '../shared/geometry.js';\nimport type { BezierParams } from '../shared/easing.js';\nimport type { ResolvedTheme } from '../theme/index.js';\nimport type { ActionKind } from '../capture/events.js';\n\nexport interface OutputProfile {\n width: number;\n height: number;\n fps: number;\n /** Output-px margins content must respect; bottom includes the caption band. */\n safeArea: { top: number; right: number; bottom: number; left: number };\n zoomQuantums: number[];\n /** Minimum rendered size (output px) of a focus rect's smaller dimension. */\n minFocusPx: number;\n captionMaxWidth: number;\n /**\n * The stage: footage renders inside `content` (a matte with rounded corners, shadow, and an\n * optional browser-chrome bar above it) instead of edge-to-edge. ALL camera math — planner,\n * renderer, cursor projection, verification — runs in content space via `stageContent()`,\n * so plan and pixels can never disagree about where footage lives. Absent = full-frame.\n */\n stage?: {\n /** Output-px rect the footage is drawn into. */\n content: Rect;\n /** Height of the browser-chrome bar drawn directly above `content` (0 = none). */\n chromeH: number;\n radius: number;\n };\n}\n\n/** The rect footage renders into: the stage's content when present, else the full frame. */\nexport function stageContent(profile: OutputProfile): Rect {\n return profile.stage?.content ?? { x: 0, y: 0, w: profile.width, h: profile.height };\n}\n\n/** Compute a stage for the profile: uniform matte margins + a chrome bar, preserving the\n * content's aspect (= the capture viewport's), so camera math scales cleanly. */\nexport function withStage(profile: OutputProfile, chrome: boolean): OutputProfile {\n const { width, height } = profile;\n const marginY = Math.round(height * 0.055);\n const chromeH = chrome ? Math.round(44 * (Math.min(width, height) / 1080)) : 0;\n const contentH = height - 2 * marginY - chromeH;\n const contentW = Math.round(contentH * (width / height));\n const x = Math.round((width - contentW) / 2);\n const y = marginY + chromeH;\n return {\n ...profile,\n stage: { content: { x, y, w: contentW, h: contentH }, chromeH, radius: Math.round(14 * (Math.min(width, height) / 1080)) },\n };\n}\n\nexport const PROFILE_16x9: OutputProfile = {\n width: 1920,\n height: 1080,\n fps: 30,\n safeArea: { top: 54, right: 96, bottom: 160, left: 96 },\n zoomQuantums: [1.0, 1.15, 1.3, 1.5, 1.7, 2.0],\n minFocusPx: 110,\n captionMaxWidth: 1040,\n};\n\n/** Portrait: reserve more top/bottom for platform UI chrome; captions span most of the width. */\nexport const PROFILE_9x16: OutputProfile = {\n width: 1080,\n height: 1920,\n fps: 30,\n safeArea: { top: 230, right: 56, bottom: 320, left: 56 },\n zoomQuantums: [1.0, 1.15, 1.3, 1.5, 1.7, 2.0],\n minFocusPx: 96,\n captionMaxWidth: 980,\n};\n\nexport const PROFILE_1x1: OutputProfile = {\n width: 1080,\n height: 1080,\n fps: 30,\n safeArea: { top: 80, right: 72, bottom: 200, left: 72 },\n zoomQuantums: [1.0, 1.15, 1.3, 1.5, 1.7, 2.0],\n minFocusPx: 100,\n captionMaxWidth: 940,\n};\n\n/** Resolve the output profile for an aspect, overlaying the spec's resolution + fps. */\nexport function profileForAspect(\n aspect: '16:9' | '9:16' | '1:1',\n resolution: { w: number; h: number },\n fps: number,\n): OutputProfile {\n const base = aspect === '9:16' ? PROFILE_9x16 : aspect === '1:1' ? PROFILE_1x1 : PROFILE_16x9;\n const scaleX = resolution.w / base.width;\n const scaleY = resolution.h / base.height;\n return {\n ...base,\n width: resolution.w,\n height: resolution.h,\n fps,\n safeArea: {\n top: Math.round(base.safeArea.top * scaleY),\n bottom: Math.round(base.safeArea.bottom * scaleY),\n left: Math.round(base.safeArea.left * scaleX),\n right: Math.round(base.safeArea.right * scaleX),\n },\n captionMaxWidth: Math.round(base.captionMaxWidth * scaleX),\n };\n}\n\nexport type TimeSegment =\n | { kind: 'source'; outStart: number; outEnd: number; srcStart: number; srcEnd: number }\n | { kind: 'freeze'; outStart: number; outEnd: number; srcAt: number }\n | { kind: 'card'; outStart: number; outEnd: number; cardId: string };\n\nexport interface CameraKeyframe {\n tOut: number;\n state: CameraState;\n /** Ease applied travelling from the previous keyframe to this one. */\n ease: BezierParams;\n}\n\nexport interface CursorSegment {\n tStart: number;\n tEnd: number;\n /** Arc-length-resampled polyline in viewport space. */\n path: Point[];\n clickAtEnd: boolean;\n}\n\nexport interface ClickRipple {\n tOut: number;\n /** Viewport space. */\n x: number;\n y: number;\n}\n\nexport interface CaptionOverlay {\n kind: 'caption';\n stepRef: string;\n ordinal: number;\n totalSteps: number;\n /** Whether to draw the numbered step badge (off for demo/release/social/factual styles). */\n showBadge: boolean;\n text: string;\n lines: string[];\n fontPx: number;\n /** Output-space card rect as rendered. */\n box: Rect;\n tStart: number;\n tEnd: number;\n shrunk: boolean;\n truncated: boolean;\n}\n\nexport interface TitleCardOverlay {\n kind: 'titleCard';\n cardId: string;\n title: string;\n subtitle?: string;\n tStart: number;\n tEnd: number;\n}\n\nexport interface DipTransition {\n kind: 'dip';\n tStart: number;\n tEnd: number;\n /** 'in' fades FROM the theme background into footage (post-title); 'out' fades footage\n * INTO the background (pre-end-card). Default 'in'. */\n direction?: 'in' | 'out';\n}\n\n/**\n * Act→react camera windows for a step that clicks one place and focuses another (\"click here,\n * LOOK there\"): the camera frames the action target around the beat, then hands off to the\n * focused payoff for the settled hold. Shared by the planner (to emit the handoff) and the\n * verifier (to assert each rect during ITS window) so plan and checks agree by construction.\n * Returns null when the step has no handoff (single rect, or too little hold to travel in).\n */\nexport function actReactWindows(step: StepMapEntry): {\n act: { rect: Rect; from: number; to: number };\n react: { rect: Rect; from: number; to: number };\n} | null {\n if (!step.focusRectVp || !step.targetRectVp) return null;\n if (step.focus === 'target' || step.focus === 'wide') return null;\n if (step.outEnd - step.outBeat < 1600) return null; // not enough hold to travel and settle\n return {\n act: { rect: step.targetRectVp, from: step.outBeat - 60, to: step.outBeat + 400 },\n react: { rect: step.focusRectVp, from: step.outBeat + 1100, to: step.outEnd },\n };\n}\n\n/** A persistent elapsed-time readout (bug-repro evidence). Rendered against the output clock. */\nexport interface ElapsedClockOverlay {\n kind: 'elapsedClock';\n tStart: number;\n tEnd: number;\n /** Output ms to subtract so the clock reads 0 at the first real action, not the title card. */\n zeroAtMs: number;\n}\n\n/** A brief scene-title label at each new scene (demo/before-after narrative structure). */\nexport interface ChapterLabelOverlay {\n kind: 'chapterLabel';\n title: string;\n ordinal: number;\n tStart: number;\n tEnd: number;\n}\n\n/** Closing card for a FAILED capture: the failure clip ends on what broke and why. */\nexport interface FailureCardOverlay {\n kind: 'failureCard';\n stepRef: string;\n message: string;\n tStart: number;\n tEnd: number;\n}\n\nexport type OverlayEntry =\n | CaptionOverlay\n | TitleCardOverlay\n | DipTransition\n | ElapsedClockOverlay\n | ChapterLabelOverlay\n | FailureCardOverlay;\n\nexport interface StepMapEntry {\n stepRef: string;\n sceneId: string;\n ordinal: number;\n kind: ActionKind;\n locator?: string;\n /** True for masked type steps — their visible effect is intentionally suppressed. */\n masked?: boolean;\n /** Viewport-space target rect at action time (bboxPre), when the step had a target. */\n targetRectVp?: Rect;\n /** Camera hint from the spec: 'target' | 'wide' | a locator string. */\n focus?: string;\n /** Shot-boundary control from the spec: 'cut' | 'continue'. */\n shot?: string;\n /** Measured rect of a locator-valued focus hint at the settled moment — the payoff the\n * camera should frame instead of the action target (\"click here, look there\"). */\n focusRectVp?: Rect;\n outStart: number;\n /** Output-clock moment the action lands. */\n outBeat: number;\n outEnd: number;\n srcAction: number;\n srcSettled: number;\n}\n\nexport interface ComposeDiagnostics {\n overflows: { stepRef: string; text: string; action: 'shrunk' | 'truncated' }[];\n cameraFallbacks: string[];\n clockWarnings: string[];\n}\n\nexport interface ComposeManifest {\n schema: 'playhead/compose@1';\n profile: OutputProfile;\n viewport: { w: number; h: number };\n durationMs: number;\n totalFrames: number;\n segments: TimeSegment[];\n camera: CameraKeyframe[];\n cursor: CursorSegment[];\n ripples: ClickRipple[];\n overlays: OverlayEntry[];\n /** Cross-dissolve windows at scene boundaries: old footage (held at srcFrom) fades into new. */\n transitions?: { tStart: number; tEnd: number; srcFrom: number }[];\n steps: StepMapEntry[];\n theme: ResolvedTheme;\n diagnostics: ComposeDiagnostics;\n bundleHashes: { events: string; framesIndex: string };\n videoSha256?: string;\n /** Present when voice narration was muxed in. `clips` records where each spoken line landed\n * on the output clock, so verification can reason about voice-covered windows. */\n audio?: {\n narrated: boolean;\n provider: string;\n voice: string;\n lines: number;\n clips?: { stepRef: string; tStart: number; durMs: number }[];\n };\n}\n","import type { OutputKind } from '../spec/schema.js';\n\nexport type CaptionStyle = 'instruction' | 'factual' | 'chapter';\n\n/** How a given output kind is composed — the same capture, a different treatment. */\nexport interface KindProfile {\n kind: OutputKind;\n /** Default pacing when the spec doesn't set one. */\n pacing: 'relaxed' | 'normal' | 'brisk';\n /** Caption phrasing: instructional (\"Click X\"), factual repro (\"Step 1 — click X\"), or narrative. */\n captionStyle: CaptionStyle;\n /** Prefix each caption with its number (\"1.\", \"2.\" …). */\n numberedCaptions: boolean;\n /** Draw a running elapsed-time clock (bug evidence). */\n elapsedClock: boolean;\n /** Insert a full-frame chapter card at each new scene (demo narrative structure). */\n chapterCards: boolean;\n /** Hold on the final state this long (ms) — bug-repro dwells on the defect. */\n outroMs: number;\n /** Typed input is shown as evidence even in fields that look sensitive (repro needs the values). */\n showTypedInput: boolean;\n /** Composition-driven camera emphasis + click spotlights. Off for bug-repro, which must stay\n * a literal record of the screen. */\n cameraEmphasis: boolean;\n /** Render footage on a stage (matte + rounded card + browser chrome) instead of edge-to-edge. */\n stage: boolean;\n}\n\nconst BASE: Omit<KindProfile, 'kind'> = {\n pacing: 'normal',\n captionStyle: 'instruction',\n numberedCaptions: true,\n elapsedClock: false,\n chapterCards: false,\n outroMs: 1600,\n showTypedInput: true,\n cameraEmphasis: true,\n stage: true,\n};\n\nconst PROFILES: Record<OutputKind, KindProfile> = {\n walkthrough: { kind: 'walkthrough', ...BASE },\n demo: {\n kind: 'demo',\n ...BASE,\n pacing: 'relaxed',\n captionStyle: 'chapter',\n numberedCaptions: false,\n chapterCards: true,\n outroMs: 2200,\n },\n 'bug-repro': {\n kind: 'bug-repro',\n ...BASE,\n pacing: 'normal',\n captionStyle: 'factual',\n numberedCaptions: true,\n elapsedClock: true,\n outroMs: 3000,\n // A repro is EVIDENCE: no directorial zoom, no spotlights, no matte — the literal screen.\n cameraEmphasis: false,\n stage: false,\n },\n 'before-after': { kind: 'before-after', ...BASE, pacing: 'normal', chapterCards: true, numberedCaptions: false },\n release: { kind: 'release', ...BASE, pacing: 'brisk', numberedCaptions: false, outroMs: 1400 },\n social: { kind: 'social', ...BASE, pacing: 'brisk', numberedCaptions: false, outroMs: 1400 },\n};\n\nexport function kindProfile(kind: OutputKind): KindProfile {\n return PROFILES[kind] ?? PROFILES.walkthrough;\n}\n","import type { Rect, Point } from '../shared/geometry.js';\n\n/** All event/frame times are milliseconds relative to capture start, on one normalized clock. */\n\nexport interface TargetInfo {\n role: string | null;\n accessibleName: string | null;\n /** Viewport-relative (client) CSS px — exactly the space the captured frames show. */\n bbox: Rect;\n /** Window scroll offsets at measure time, CSS px. */\n scroll: Point;\n}\n\nexport interface CursorWaypoint {\n x: number;\n y: number;\n t: number;\n}\n\nexport type ActionKind =\n | 'goto'\n | 'click'\n | 'dblclick'\n | 'hover'\n | 'type'\n | 'press'\n | 'select'\n | 'scroll'\n | 'expect'\n | 'wait';\n\nexport interface ActionEvent {\n type: 'action';\n kind: ActionKind;\n sceneId: string;\n stepIndex: number;\n /** Global 1-based step number across the whole spec. */\n ordinal: number;\n locator?: string;\n targetPre?: TargetInfo | null;\n targetPost?: TargetInfo | null;\n cursorPath: CursorWaypoint[];\n /** Redacted to bullets when masked — the real string never enters any artifact. */\n typedText?: string;\n masked?: boolean;\n /** Caption override from the spec, carried through for the compositor. */\n caption?: string;\n /** Spoken-line override from the spec (TTS narration), carried as a record — the live spec\n * wins at compose time. */\n narration?: string;\n /** Camera-shot boundary control from the spec ('cut' | 'continue'). */\n shot?: string;\n /** Camera hint from the spec: 'target' | 'wide' | a locator string. */\n focus?: string;\n /** When `focus` names a locator, its measured geometry at the settled moment — the payoff\n * rect the camera should frame (\"click here, look there\"). */\n focusTarget?: TargetInfo | null;\n tStart: number;\n /** Moment the action lands (mouse-down, first keystroke, key chord). */\n tAction: number;\n /** Action fully delivered (mouse-up, last keystroke). */\n tActionEnd: number;\n /** UI settled after the action (network idle + layout stable). */\n tSettled: number;\n}\n\nexport interface NavigationEvent {\n type: 'navigation';\n url: string;\n t: number;\n}\n\nexport type CaptureEvent = ActionEvent | NavigationEvent;\n\nexport interface EventLogMeta {\n viewport: { w: number; h: number };\n dpr: number;\n /** Actual pixel dimensions of captured frames (source of truth for frame-space scale). */\n frameW: number;\n frameH: number;\n clockOffsetMs: number;\n startedAtIso: string;\n durationMs: number;\n appUrl: string;\n}\n\nexport interface EventLog {\n schema: 'playhead/events@1';\n meta: EventLogMeta;\n events: CaptureEvent[];\n}\n\nexport function actionEvents(log: EventLog): ActionEvent[] {\n return log.events.filter((e): e is ActionEvent => e.type === 'action');\n}\n\nexport function navigationEvents(log: EventLog): NavigationEvent[] {\n return log.events.filter((e): e is NavigationEvent => e.type === 'navigation');\n}\n","/** Narration placement constants, shared by the timeline (dwell fitting) and the muxer. */\n\n/** A step's spoken line starts this long after the step (and its caption) begin. */\nexport const AUDIO_LEAD_MS = 150;\n/** Silence kept after a spoken line finishes before the step is allowed to end. */\nexport const AUDIO_TAIL_MS = 450;\n","import type { EventLog, ActionEvent, ActionKind } from '../../capture/events.js';\nimport { actionEvents } from '../../capture/events.js';\nimport type { TimeSegment, StepMapEntry } from '../types.js';\nimport { AUDIO_LEAD_MS, AUDIO_TAIL_MS } from '../../audio/timing.js';\n\nexport interface PacingConfig {\n factor: number;\n titleCardMs: number;\n introMaxMs: number;\n outroMs: number;\n idleGapMaxMs: number;\n idleGapOutMs: number;\n minStepMs: number;\n maxTypeOutMs: number;\n holds: Record<ActionKind, number>;\n}\n\nexport function pacingConfig(mode: 'relaxed' | 'normal' | 'brisk', kind?: { outroMs: number }): PacingConfig {\n const factor = mode === 'relaxed' ? 1.25 : mode === 'brisk' ? 0.8 : 1;\n return {\n factor,\n titleCardMs: 2200,\n introMaxMs: 1200,\n outroMs: kind?.outroMs ?? 1600,\n idleGapMaxMs: 1500,\n idleGapOutMs: 400,\n minStepMs: 1800 * factor,\n maxTypeOutMs: 4500,\n holds: {\n goto: 1200 * factor,\n click: 600 * factor,\n dblclick: 600 * factor,\n hover: 450 * factor,\n type: 450 * factor,\n press: 450 * factor,\n select: 600 * factor,\n scroll: 350 * factor,\n expect: 800 * factor,\n wait: 150,\n },\n };\n}\n\nexport interface TimelinePlan {\n segments: TimeSegment[];\n steps: StepMapEntry[];\n durationMs: number;\n}\n\n/**\n * Build the output timeline: title card, per-step source spans with compose-time\n * pacing (idle-gap trimming, post-action freezes, min-step extension), and an\n * outro hold on the final state.\n */\nexport function buildTimeline(log: EventLog, cfg: PacingConfig, audioMs?: Map<string, number>): TimelinePlan {\n const events = actionEvents(log);\n const segments: TimeSegment[] = [];\n const steps: StepMapEntry[] = [];\n\n segments.push({ kind: 'card', outStart: 0, outEnd: cfg.titleCardMs, cardId: 'title' });\n let out = cfg.titleCardMs;\n let src = events.length > 0 ? Math.max(0, events[0]!.tStart - cfg.introMaxMs) : 0;\n\n for (const e of events) {\n // Gap between the previous settle and this step's start.\n const gap = e.tStart - src;\n if (gap > 1) {\n const outDur = gap > cfg.idleGapMaxMs ? cfg.idleGapOutMs : gap;\n segments.push({ kind: 'source', outStart: out, outEnd: out + outDur, srcStart: src, srcEnd: e.tStart });\n out += outDur;\n }\n const stepOutStart = out;\n\n // Action span at natural rate (typing capped and sped up uniformly).\n const srcEnd = Math.max(e.tSettled, e.tActionEnd, e.tStart + 1);\n const spanSrc = srcEnd - e.tStart;\n let spanOut = spanSrc;\n if (e.kind === 'type' && spanSrc > cfg.maxTypeOutMs) spanOut = cfg.maxTypeOutMs;\n segments.push({ kind: 'source', outStart: out, outEnd: out + spanOut, srcStart: e.tStart, srcEnd });\n const outBeat = out + (e.tAction - e.tStart) * (spanOut / spanSrc);\n out += spanOut;\n\n // Post-action freeze: fixed hold, extended to satisfy the minimum step duration.\n let hold = cfg.holds[e.kind];\n if (out + hold - stepOutStart < cfg.minStepMs) hold = cfg.minStepMs - (out - stepOutStart);\n // Narration-driven pacing: grow the hold so the step lasts long enough for its\n // spoken line (lead-in + speech + tail) to finish before the step ends.\n const aud = audioMs?.get(`${e.sceneId}/${e.stepIndex}`);\n if (aud && aud > 0) {\n const need = AUDIO_LEAD_MS + aud + AUDIO_TAIL_MS;\n const have = out - stepOutStart + hold;\n if (have < need) hold += need - have;\n }\n // Act→react pacing: a step whose focus hands the camera off to a payoff element needs\n // enough post-beat hold for the travel plus a settled look at the destination.\n if (e.focusTarget && e.focus && e.focus !== 'target' && e.focus !== 'wide') {\n const needAfterBeat = 2100;\n const haveAfterBeat = out + hold - outBeat;\n if (haveAfterBeat < needAfterBeat) hold += needAfterBeat - haveAfterBeat;\n }\n if (hold > 0.5) {\n segments.push({ kind: 'freeze', outStart: out, outEnd: out + hold, srcAt: srcEnd });\n out += hold;\n }\n\n steps.push({\n stepRef: `${e.sceneId}/${e.stepIndex}`,\n sceneId: e.sceneId,\n ordinal: e.ordinal,\n kind: e.kind,\n ...(e.locator ? { locator: e.locator } : {}),\n ...(e.masked ? { masked: true } : {}),\n ...(e.targetPre ? { targetRectVp: e.targetPre.bbox } : {}),\n ...(e.focus ? { focus: e.focus } : {}),\n ...(e.shot ? { shot: e.shot } : {}),\n ...(e.focusTarget ? { focusRectVp: e.focusTarget.bbox } : {}),\n outStart: stepOutStart,\n outBeat,\n outEnd: out,\n srcAction: e.tAction,\n srcSettled: srcEnd,\n });\n src = srcEnd;\n }\n\n // Outro: hold the final state.\n const lastSrc = Math.max(src, log.meta.durationMs - 1);\n segments.push({ kind: 'freeze', outStart: out, outEnd: out + cfg.outroMs, srcAt: lastSrc });\n out += cfg.outroMs;\n\n return { segments, steps, durationMs: out };\n}\n\n/** Map an output time to a source time (null on card segments). */\nexport function sampleSource(segments: TimeSegment[], tOut: number): { srcAt: number | null; segment: TimeSegment } {\n const seg = segmentAt(segments, tOut);\n switch (seg.kind) {\n case 'card':\n return { srcAt: null, segment: seg };\n case 'freeze':\n return { srcAt: seg.srcAt, segment: seg };\n case 'source': {\n const u = (tOut - seg.outStart) / Math.max(1e-6, seg.outEnd - seg.outStart);\n return { srcAt: seg.srcStart + u * (seg.srcEnd - seg.srcStart), segment: seg };\n }\n }\n}\n\nexport function segmentAt(segments: TimeSegment[], tOut: number): TimeSegment {\n let lo = 0;\n let hi = segments.length - 1;\n if (tOut <= segments[0]!.outStart) return segments[0]!;\n if (tOut >= segments[hi]!.outEnd) return segments[hi]!;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (segments[mid]!.outEnd <= tOut) lo = mid + 1;\n else hi = mid;\n }\n return segments[lo]!;\n}\n\n/** Events keyed by stepRef, for callers pairing steps back to their events. */\nexport function eventByStepRef(log: EventLog): Map<string, ActionEvent> {\n const map = new Map<string, ActionEvent>();\n for (const e of actionEvents(log)) map.set(`${e.sceneId}/${e.stepIndex}`, e);\n return map;\n}\n","import type { CameraKeyframe } from '../types.js';\nimport type { CameraState } from '../../shared/geometry.js';\nimport { cubicBezier } from '../../shared/easing.js';\n\n/**\n * Sample the camera path at an output time. Keyframes are (time, state, ease-from-previous);\n * holds are expressed as consecutive keyframes with identical states. Zoom interpolates in\n * log space (linear zoom feels like it accelerates).\n */\nexport function sampleCamera(keyframes: CameraKeyframe[], tOut: number): CameraState {\n if (keyframes.length === 0) return { cx: 0, cy: 0, zoom: 1 };\n if (tOut <= keyframes[0]!.tOut) return { ...keyframes[0]!.state };\n const last = keyframes[keyframes.length - 1]!;\n if (tOut >= last.tOut) return { ...last.state };\n\n let lo = 0;\n let hi = keyframes.length - 1;\n while (lo < hi - 1) {\n const mid = (lo + hi) >> 1;\n if (keyframes[mid]!.tOut <= tOut) lo = mid;\n else hi = mid;\n }\n const a = keyframes[lo]!;\n const b = keyframes[hi]!;\n const u = (tOut - a.tOut) / Math.max(1e-6, b.tOut - a.tOut);\n const e = cubicBezier(b.ease, u);\n return {\n cx: a.state.cx + (b.state.cx - a.state.cx) * e,\n cy: a.state.cy + (b.state.cy - a.state.cy) * e,\n zoom: Math.exp(Math.log(a.state.zoom) + (Math.log(b.state.zoom) - Math.log(a.state.zoom)) * e),\n };\n}\n","import type { CameraKeyframe, OutputProfile, StepMapEntry } from '../types.js';\nimport { stageContent, actReactWindows } from '../types.js';\nimport type { EventLog } from '../../capture/events.js';\nimport { navigationEvents } from '../../capture/events.js';\nimport {\n type CameraPlane,\n type CameraState,\n type Rect,\n clamp,\n clampCamera,\n minZoom,\n padRect,\n projectRect,\n rectCenter,\n rectContains,\n rectUnion,\n} from '../../shared/geometry.js';\nimport { EASE_PAN, EASE_ZOOM } from '../../shared/easing.js';\nimport { sampleCamera } from './interpolate.js';\n\nconst FOCUS_PAD_VP = 24;\nconst SHOT_MAX_GAP_MS = 4000;\nconst PAN_DEADBAND_VP = 48;\nconst TRAVEL_MIN_MS = 500;\nconst TRAVEL_MAX_MS = 900;\nconst ARRIVE_LEAD_MS = 80;\n/** Target rendered height (output px) the zoom aims to give the smallest target — comfortably\n * above the verifier's 28px legibility floor so quantization rounding stays safe. */\nconst LEGIBLE_TARGET_PX = 34;\n\ninterface Shot {\n stepRefs: string[];\n sceneId: string;\n focus: Rect;\n /** Smallest unpadded target dimension across the shot's members (viewport px) — this, not the\n * union size, is what the legibility zoom must satisfy so every member stays readable. */\n minTargetDim: number;\n wide: boolean;\n outStart: number;\n firstBeat: number;\n outEnd: number;\n zoomIndex: number;\n state?: CameraState;\n}\n\nexport interface CameraPlanResult {\n keyframes: CameraKeyframe[];\n fallbacks: string[];\n}\n\n/**\n * Plan the camera path from measured step geometry. Craft rules: quantized zoom levels,\n * legibility-driven zoom selection, caption-safe-area bias, pull-backs on navigation and\n * long pans, and an analytic constraint pass that guarantees each target stays framed.\n */\nexport function planCamera(\n steps: StepMapEntry[],\n log: EventLog,\n profile: OutputProfile,\n durationMs: number,\n opts?: { emphasis?: boolean },\n): CameraPlanResult {\n // The camera projects into the STAGE's content rect (or the full frame without a stage):\n // one shared space for planner, renderer, cursor, and verification.\n const content = stageContent(profile);\n const plane: CameraPlane = {\n vpW: log.meta.viewport.w,\n vpH: log.meta.viewport.h,\n outW: content.w,\n outH: content.h,\n };\n const emphasis = opts?.emphasis ?? true;\n const fallbacks: string[] = [];\n\n // Sharpness-bounded zoom quantums: the frame buffer only has frameW real pixels across.\n // Upscales beyond ~1.28x read as soft, so cap quantums there. (The stage helps here: content\n // renders smaller than the frame, so the same capture supports deeper sharp zooms.)\n const sharpZoom = log.meta.frameW > 0 ? log.meta.frameW / content.w : 1.3;\n const zMaxAllowed = Math.max(minZoom(plane), sharpZoom * 1.28);\n const quantums = profile.zoomQuantums.filter((q) => q <= zMaxAllowed + 1e-6);\n if (quantums.length === 0) quantums.push(1);\n\n const navTimes = navigationEvents(log).map((n) => n.t);\n const shots = groupShots(steps, navTimes, plane, durationMs);\n\n for (let attempt = 0; attempt < 4; attempt++) {\n for (const shot of shots) shot.state = shotState(shot, quantums, plane, profile, emphasis);\n const keyframes = emitKeyframes(shots, plane, durationMs);\n const violation = checkConstraints(keyframes, steps, plane, profile);\n if (!violation) return { keyframes, fallbacks };\n\n // An act→react step owns TWO shots with the same stepRef — pick the one whose time window\n // contains the violation, falling back to stepRef membership.\n const shot =\n shots.find(\n (s) => s.stepRefs.includes(violation.stepRef) && violation.tOut >= s.outStart && violation.tOut <= s.outEnd,\n ) ?? shots.find((s) => s.stepRefs.includes(violation.stepRef));\n if (!shot || shot.zoomIndex === 0 || shot.wide) {\n fallbacks.push(`${violation.stepRef}: unresolvable framing violation — falling back to wide`);\n if (shot) shot.wide = true;\n else break;\n } else {\n shot.zoomIndex -= 1;\n fallbacks.push(`${violation.stepRef}: reduced shot zoom to satisfy framing constraints`);\n }\n }\n for (const shot of shots) shot.state = shotState(shot, quantums, plane, profile, emphasis);\n return { keyframes: emitKeyframes(shots, plane, durationMs), fallbacks };\n}\n\nfunction groupShots(steps: StepMapEntry[], navTimes: number[], plane: CameraPlane, durationMs: number): Shot[] {\n const shots: Shot[] = [];\n let current: Shot | null = null;\n\n const navBetween = (a: number, b: number) => navTimes.some((t) => t > a && t <= b);\n\n for (const step of steps) {\n // Act→react: the step clicks one place and focuses another, with enough hold to travel.\n // Emit TWO shots — frame the action target through the beat, then hand the camera off to\n // the payoff for the settled hold (\"click here, look there\" inside one step).\n const handoff = actReactWindows(step);\n if (handoff) {\n const actFocus = padRect(handoff.act.rect, FOCUS_PAD_VP);\n const reactFocus = padRect(handoff.react.rect, FOCUS_PAD_VP);\n shots.push({\n stepRefs: [step.stepRef],\n sceneId: step.sceneId,\n focus: actFocus,\n minTargetDim: Math.min(handoff.act.rect.w, handoff.act.rect.h),\n wide: false,\n outStart: step.outStart,\n firstBeat: step.outBeat,\n outEnd: handoff.act.to,\n zoomIndex: Number.MAX_SAFE_INTEGER,\n });\n shots.push({\n stepRefs: [step.stepRef],\n sceneId: step.sceneId,\n focus: reactFocus,\n minTargetDim: Math.min(handoff.react.rect.w, handoff.react.rect.h),\n wide: false,\n outStart: handoff.act.to,\n firstBeat: handoff.react.from, // arrive by the react window's start\n outEnd: step.outEnd,\n zoomIndex: Number.MAX_SAFE_INTEGER,\n });\n current = null; // never merge across a handoff\n continue;\n }\n\n let rect = step.kind === 'goto' ? undefined : step.targetRectVp;\n // goto and scroll are wide by nature: goto changes everything; a scroll's meaning is the\n // motion, not a specific small element (so scroll targets are exempt from the legibility\n // floor elsewhere — they need only be in frame).\n let wide = !rect || step.kind === 'goto' || step.kind === 'scroll';\n // The spec's focus hint is AUTHORITY, not a suggestion: 'wide' forces a wide shot; 'target'\n // forces this step's own framed shot (never merged away); a locator-valued focus swaps the\n // framed rect for the measured payoff element — this is what lets a goto or a sidebar click\n // frame the thing that CHANGED rather than the thing that was clicked.\n if (step.focus === 'wide') {\n wide = true;\n } else if (step.focusRectVp) {\n rect = step.focusRectVp;\n wide = false;\n } else if (step.focus === 'target' && rect) {\n wide = false;\n }\n // Spec shot control: 'cut' forces this step into a fresh shot; 'continue' merges into the\n // previous shot even when the heuristic would split — the author's cut list wins.\n if (step.shot === 'cut') current = null;\n const forceContinue = step.shot === 'continue';\n if (forceContinue && current && rect && current.sceneId === step.sceneId) {\n current.stepRefs.push(step.stepRef);\n current.focus = rectUnion(current.focus, padRect(rect, FOCUS_PAD_VP));\n current.minTargetDim = Math.min(current.minTargetDim, Math.min(rect.w, rect.h));\n current.outEnd = step.outEnd;\n continue;\n }\n const noMerge = step.focus === 'target' || step.focusRectVp !== undefined;\n // A shot never spans scenes: hash-route changes don't fire a navigation event, so scene\n // identity — not navBetween alone — is what keeps a tour's views from merging into one\n // un-zoomable mega-shot.\n if (current && !noMerge && current.sceneId === step.sceneId && !current.wide && !wide && rect) {\n const prevSrc = current.stepRefs.length > 0 ? steps.find((s) => s.stepRef === current!.stepRefs[current!.stepRefs.length - 1])!.srcSettled : 0;\n const union = rectUnion(current.focus, padRect(rect, FOCUS_PAD_VP));\n // A merge must keep the SMALLEST member legible: if the union can only be shown at a zoom\n // below what the smallest target needs, merging would dilute it (a small pipeline card\n // pulled into a wide modal shot renders too small) — so keep them as separate shots.\n const baseScale = plane.outW / plane.vpW;\n const mergedMinDim = Math.min(current.minTargetDim, Math.min(rect.w, rect.h));\n const zNeeded = Math.min(LEGIBLE_TARGET_PX / (mergedMinDim * baseScale), 1.6);\n const zFitUnion = fitZoom(union, plane) * 0.92;\n const fitsTogether = fitZoom(union, plane) >= 1.2 && zFitUnion >= zNeeded - 0.02;\n const closeInTime = step.outStart - current.outEnd < SHOT_MAX_GAP_MS;\n if (fitsTogether && closeInTime && !navBetween(prevSrc, step.srcAction)) {\n current.stepRefs.push(step.stepRef);\n current.focus = union;\n current.minTargetDim = Math.min(current.minTargetDim, Math.min(rect.w, rect.h));\n current.outEnd = step.outEnd;\n continue;\n }\n }\n current = {\n stepRefs: [step.stepRef],\n sceneId: step.sceneId,\n focus: rect ? padRect(rect, FOCUS_PAD_VP) : { x: 0, y: 0, w: plane.vpW, h: plane.vpH },\n minTargetDim: rect ? Math.min(rect.w, rect.h) : Math.min(plane.vpW, plane.vpH),\n wide,\n outStart: step.outStart,\n firstBeat: step.outBeat,\n outEnd: step.outEnd,\n zoomIndex: Number.MAX_SAFE_INTEGER, // resolved in shotState\n };\n shots.push(current);\n }\n if (shots.length > 0) shots[shots.length - 1]!.outEnd = Math.min(shots[shots.length - 1]!.outEnd, durationMs);\n return shots;\n}\n\n/** Max zoom at which a viewport rect still fits in the visible window with margin. */\nfunction fitZoom(rect: Rect, plane: CameraPlane): number {\n const zw = plane.vpW / rect.w;\n const zh = (plane.vpW * plane.outH) / plane.outW / rect.h;\n return Math.min(zw, zh);\n}\n\n/** Fraction of the fit-zoom a focus rect should occupy when the camera emphasises it: at 0.5\n * the subject fills roughly half the frame's limiting dimension — close enough to direct the\n * eye, wide enough to keep context. This, not legibility, is what makes shots feel FRAMED. */\nconst OCCUPANCY = 0.5;\n\nfunction shotState(\n shot: Shot,\n quantums: number[],\n plane: CameraPlane,\n profile: OutputProfile,\n emphasis: boolean,\n): CameraState {\n const zMin = minZoom(plane);\n if (shot.wide) {\n return clampCamera({ cx: plane.vpW / 2, cy: rectCenter(shot.focus).y, zoom: zMin }, plane);\n }\n const baseScale = plane.outW / plane.vpW;\n // Legibility is driven by the SMALLEST member target (so a small element merged into a large\n // shot still gets enough zoom), while fit is driven by the whole union (so nothing is cropped).\n const minDim = Math.max(6, shot.minTargetDim);\n const zLegibility = LEGIBLE_TARGET_PX / (minDim * baseScale);\n const zFit = fitZoom(shot.focus, plane) * 0.92;\n\n // Composition: zoom is a DIRECTORIAL choice, not just a legibility floor. Without this, any\n // target above ~23 viewport px resolves to zoom 1.0 and the whole video plays wide and flat.\n const zComposition = emphasis ? OCCUPANCY * fitZoom(shot.focus, plane) : 0;\n const zWant = Math.max(zLegibility, zComposition);\n\n // Choose the smallest quantum ≥ the wanted zoom (round UP — an under-framed subject is the\n // defect we most want to avoid), but never past what fits without cropping.\n const maxFit = Math.min(zFit, quantums[quantums.length - 1]!);\n let zoomIndex = 0;\n let reachedWant = false;\n for (let i = 0; i < quantums.length; i++) {\n if (quantums[i]! > maxFit + 1e-6) break;\n zoomIndex = i; // largest quantum that still fits, as a fallback\n if (!reachedWant && quantums[i]! >= zWant - 1e-6) {\n zoomIndex = i;\n reachedWant = true;\n break;\n }\n }\n shot.zoomIndex = Math.min(shot.zoomIndex, zoomIndex);\n const zoom = Math.max(quantums[shot.zoomIndex]!, zMin);\n\n const center = rectCenter(shot.focus);\n let state = clampCamera({ cx: center.x, cy: center.y, zoom }, plane);\n\n // Bias the focus rect into the content safe area (out of the caption band).\n for (let i = 0; i < 3; i++) {\n const proj = projectRect(shot.focus, state, plane);\n const safe = contentArea(profile);\n let dyOut = 0;\n if (proj.y + proj.h > safe.y + safe.h) dyOut = proj.y + proj.h - (safe.y + safe.h);\n else if (proj.y < safe.y) dyOut = proj.y - safe.y;\n let dxOut = 0;\n if (proj.x + proj.w > safe.x + safe.w) dxOut = proj.x + proj.w - (safe.x + safe.w);\n else if (proj.x < safe.x) dxOut = proj.x - safe.x;\n if (Math.abs(dxOut) < 1 && Math.abs(dyOut) < 1) break;\n const visW = plane.vpW / state.zoom;\n const scale = visW / plane.outW;\n state = clampCamera({ cx: state.cx + dxOut * scale, cy: state.cy + dyOut * scale, zoom: state.zoom }, plane);\n }\n return state;\n}\n\n/** The safe area, expressed in PLANE space (stage content coords when a stage is set): frame\n * margins translated into the content rect, with a small floor so it never collapses. */\nexport function contentArea(profile: OutputProfile): Rect {\n const s = stageContent(profile);\n const left = Math.max(profile.safeArea.left - s.x, 8);\n const top = Math.max(profile.safeArea.top - s.y, 8);\n const right = Math.min(s.w - 8, profile.width - profile.safeArea.right - s.x);\n const bottom = Math.min(s.h - 8, profile.height - profile.safeArea.bottom - s.y);\n return { x: left, y: top, w: Math.max(16, right - left), h: Math.max(16, bottom - top) };\n}\n\nfunction emitKeyframes(shots: Shot[], plane: CameraPlane, durationMs: number): CameraKeyframe[] {\n const kfs: CameraKeyframe[] = [];\n const wideState = clampCamera({ cx: plane.vpW / 2, cy: plane.vpH / 2, zoom: minZoom(plane) }, plane);\n let prevState = wideState;\n let prevEnd = 0;\n kfs.push({ tOut: 0, state: wideState, ease: EASE_ZOOM });\n\n for (const shot of shots) {\n const target = shot.state!;\n const panDist = Math.hypot(target.cx - prevState.cx, target.cy - prevState.cy);\n const zoomChanged = Math.abs(Math.log(target.zoom / prevState.zoom)) > 0.01;\n if (panDist < PAN_DEADBAND_VP / 2 && !zoomChanged) {\n prevEnd = shot.outEnd;\n continue;\n }\n\n // Long pans while zoomed read badly: pull wide first, then dive in.\n const viaWide =\n panDist > plane.vpW * 0.6 && prevState.zoom > 1.15 && target.zoom > 1.15 ? wideState : null;\n\n const arriveBy = Math.max(shot.firstBeat - ARRIVE_LEAD_MS, shot.outStart + 100);\n const travel = clamp(300 + panDist * 0.8, TRAVEL_MIN_MS, TRAVEL_MAX_MS);\n let moveStart = Math.max(prevEnd, arriveBy - travel);\n if (viaWide) {\n const mid = Math.max(prevEnd, moveStart - 350);\n kfs.push({ tOut: mid, state: prevState, ease: EASE_PAN });\n kfs.push({ tOut: Math.min(mid + 400, arriveBy - 200), state: viaWide, ease: EASE_ZOOM });\n moveStart = Math.min(mid + 400, arriveBy - 200);\n } else {\n kfs.push({ tOut: moveStart, state: prevState, ease: EASE_PAN });\n }\n const moveEnd = Math.max(arriveBy, moveStart + 250);\n kfs.push({ tOut: moveEnd, state: target, ease: zoomChanged ? EASE_ZOOM : EASE_PAN });\n prevState = target;\n prevEnd = shot.outEnd;\n }\n\n // Final pull-back to wide during the outro.\n if (prevState.zoom > wideState.zoom + 0.01 || Math.hypot(prevState.cx - wideState.cx, prevState.cy - wideState.cy) > PAN_DEADBAND_VP) {\n const start = Math.min(prevEnd + 100, durationMs - 900);\n kfs.push({ tOut: start, state: prevState, ease: EASE_ZOOM });\n kfs.push({ tOut: Math.min(start + 800, durationMs - 50), state: wideState, ease: EASE_ZOOM });\n }\n return dedupeSorted(kfs);\n}\n\nfunction dedupeSorted(kfs: CameraKeyframe[]): CameraKeyframe[] {\n kfs.sort((a, b) => a.tOut - b.tOut);\n const out: CameraKeyframe[] = [];\n for (const kf of kfs) {\n const last = out[out.length - 1];\n if (last && kf.tOut - last.tOut < 1) {\n out[out.length - 1] = kf;\n } else {\n out.push(kf);\n }\n }\n return out;\n}\n\ninterface Violation {\n stepRef: string;\n tOut: number;\n}\n\n/**\n * The \"never crop mid-element\" guarantee: analytically sample the planned path and assert\n * every target is fully in frame (not cropped) during its hold. The comfortable safe-area\n * margin is a preference in shotState, not a hard constraint here.\n */\nfunction checkConstraints(\n keyframes: CameraKeyframe[],\n steps: StepMapEntry[],\n plane: CameraPlane,\n profile: OutputProfile,\n): Violation | null {\n // The camera projects into stage-content space, so the containment frame is the content rect.\n const content = stageContent(profile);\n const frame: Rect = { x: 0, y: 0, w: content.w, h: content.h };\n for (const step of steps) {\n // Windows to validate: an act→react step promises the ACTION target around the beat and the\n // FOCUSED payoff during the settled hold (the camera travels between — unchecked by design).\n // Otherwise: the focused rect (or the target) across the whole hold.\n const handoff = actReactWindows(step);\n const rect = step.focusRectVp ?? step.targetRectVp;\n const windows = handoff\n ? [handoff.act, handoff.react]\n : rect\n ? [{ rect, from: Math.max(step.outStart, step.outBeat - 60), to: step.outEnd }]\n : [];\n for (const w of windows) {\n for (let t = w.from; t <= w.to; t += 100) {\n const cam = sampleCamera(keyframes, t);\n const proj = projectRect(w.rect, cam, plane);\n if (!rectContains(frame, proj, 2)) {\n return { stepRef: step.stepRef, tOut: t };\n }\n }\n }\n }\n return null;\n}\n","import type { CursorSegment, ClickRipple, StepMapEntry } from '../types.js';\nimport type { EventLog } from '../../capture/events.js';\nimport { eventByStepRef } from '../timeline/pacing.js';\nimport { type Point, clamp, dist } from '../../shared/geometry.js';\nimport { minJerk } from '../../shared/easing.js';\n\nconst RESAMPLE_POINTS = 32;\nconst CLICK_KINDS = new Set(['click', 'dblclick', 'select']);\nconst POINTER_KINDS = new Set(['click', 'dblclick', 'hover', 'type', 'select']);\n\nexport interface CursorPlan {\n segments: CursorSegment[];\n ripples: ClickRipple[];\n restStart: Point;\n}\n\n/**\n * Re-synthesize cursor motion on the output clock: recorded waypoints give the path SHAPE,\n * arrival is re-timed so the cursor lands on the target exactly at the action beat with a\n * minimum-jerk profile.\n */\nexport function planCursor(steps: StepMapEntry[], log: EventLog): CursorPlan {\n const events = eventByStepRef(log);\n const segments: CursorSegment[] = [];\n const ripples: ClickRipple[] = [];\n let rest: Point = { x: log.meta.viewport.w / 2, y: log.meta.viewport.h * 0.6 };\n const restStart = { ...rest };\n\n for (const step of steps) {\n if (!POINTER_KINDS.has(step.kind)) continue;\n const event = events.get(step.stepRef);\n if (!event || event.cursorPath.length < 2) continue;\n\n const raw: Point[] = event.cursorPath.map((w) => ({ x: w.x, y: w.y }));\n // Continuity: motion starts wherever the cursor last rested on the output clock.\n raw[0] = { ...rest };\n const path = resampleByArcLength(raw, RESAMPLE_POINTS);\n const travelDist = dist(path[0]!, path[path.length - 1]!);\n const travel = clamp(300 + travelDist * 0.6, 300, 900);\n\n const prevEnd = segments.length > 0 ? segments[segments.length - 1]!.tEnd : 0;\n const tEnd = step.outBeat;\n const tStart = Math.max(Math.min(step.outStart, tEnd - 100), tEnd - travel, prevEnd + 40);\n\n if (tEnd - tStart > 30) {\n segments.push({ tStart, tEnd, path, clickAtEnd: CLICK_KINDS.has(step.kind) });\n }\n rest = path[path.length - 1]!;\n if (CLICK_KINDS.has(step.kind)) {\n ripples.push({ tOut: step.outBeat, x: rest.x, y: rest.y });\n }\n }\n return { segments, ripples, restStart };\n}\n\n/** Position of the cursor at an output time (viewport space). */\nexport function sampleCursor(plan: CursorPlan, tOut: number): Point {\n const segs = plan.segments;\n if (segs.length === 0) return plan.restStart;\n if (tOut <= segs[0]!.tStart) return segs[0]!.path[0]!;\n\n for (let i = 0; i < segs.length; i++) {\n const s = segs[i]!;\n if (tOut < s.tStart) return segs[i - 1]!.path[segs[i - 1]!.path.length - 1]!;\n if (tOut <= s.tEnd) {\n const u = minJerk((tOut - s.tStart) / Math.max(1e-6, s.tEnd - s.tStart));\n const fi = u * (s.path.length - 1);\n const i0 = Math.floor(fi);\n const i1 = Math.min(i0 + 1, s.path.length - 1);\n const f = fi - i0;\n return {\n x: s.path[i0]!.x + (s.path[i1]!.x - s.path[i0]!.x) * f,\n y: s.path[i0]!.y + (s.path[i1]!.y - s.path[i0]!.y) * f,\n };\n }\n }\n const last = segs[segs.length - 1]!;\n return last.path[last.path.length - 1]!;\n}\n\n/** Resample a polyline to n points equally spaced by arc length. */\nfunction resampleByArcLength(points: Point[], n: number): Point[] {\n const cum: number[] = [0];\n for (let i = 1; i < points.length; i++) {\n cum.push(cum[i - 1]! + dist(points[i - 1]!, points[i]!));\n }\n const total = cum[cum.length - 1]!;\n if (total < 1e-6) return Array.from({ length: n }, () => ({ ...points[0]! }));\n const out: Point[] = [];\n let j = 0;\n for (let i = 0; i < n; i++) {\n const target = (i / (n - 1)) * total;\n while (j < cum.length - 2 && cum[j + 1]! < target) j++;\n const span = Math.max(1e-6, cum[j + 1]! - cum[j]!);\n const f = (target - cum[j]!) / span;\n out.push({\n x: points[j]!.x + (points[j + 1]!.x - points[j]!.x) * f,\n y: points[j]!.y + (points[j + 1]!.y - points[j]!.y) * f,\n });\n }\n return out;\n}\n","import type { ActionEvent } from '../capture/events.js';\nimport { parseLocator, locatorDisplayName } from '../spec/locators.js';\n\n/** Per-step text overrides from a LIVE spec, keyed by stepRef — the compose-time source of\n * truth for caption/narration text. The copies baked into events.json are only the record of\n * what was captured; preferring the live spec makes text edits a sub-second re-compose, never\n * a re-capture (capture once, compose forever — including the words). */\nexport interface StepTexts {\n caption?: string;\n narration?: string;\n}\n\n/**\n * Deterministic caption writer: turns a step + its recorded accessible label into\n * instruction text. Text resolution: live-spec caption ?? captured caption ?? auto-written.\n * Returns null for steps that produce no caption (expect/wait without caption).\n */\nexport function writeCaption(event: ActionEvent, texts?: StepTexts): string | null {\n if (texts?.caption) return texts.caption;\n if (event.caption) return event.caption;\n\n const label = bestLabel(event);\n switch (event.kind) {\n case 'click':\n return label ? `Click “${label}”` : 'Click the highlighted element';\n case 'dblclick':\n return label ? `Double-click “${label}”` : 'Double-click the highlighted element';\n case 'hover':\n return label ? `Hover over “${label}”` : 'Hover over the highlighted element';\n case 'type':\n return label ? `Enter the ${lowerFirst(label)}` : 'Enter a value';\n case 'press':\n return `Press ${event.locator ?? 'the key'}`;\n case 'select':\n return label && event.typedText\n ? `Choose “${event.typedText}” under ${label}`\n : label\n ? `Choose an option under ${label}`\n : 'Choose an option';\n case 'goto':\n return `Open ${prettyUrl(event.locator ?? '')}`;\n case 'scroll':\n return label ? `Scroll to ${label}` : 'Scroll down';\n case 'expect':\n case 'wait':\n return null;\n }\n}\n\n/**\n * The SPOKEN line for a step: live-spec narration ?? live-spec caption ?? captured narration ??\n * the caption. Narration is unconstrained by the caption card, so a spec can show a terse\n * on-screen label while the voice says the full sentence.\n */\nexport function writeNarration(event: ActionEvent, texts?: StepTexts): string | null {\n return texts?.narration ?? event.narration ?? writeCaption(event, texts);\n}\n\nfunction bestLabel(event: ActionEvent): string | null {\n const name = event.targetPre?.accessibleName?.trim();\n if (name) return truncate(name, 60);\n if (event.locator) {\n try {\n return truncate(locatorDisplayName(parseLocator(event.locator)), 60);\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction lowerFirst(s: string): string {\n // Keep acronyms/proper-looking tokens intact (\"API key\" stays, \"Email\" lowers).\n if (s.length > 1 && s[1] === s[1]!.toUpperCase() && /[A-Z]/.test(s[1]!)) return s;\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n\nfunction prettyUrl(url: string): string {\n try {\n const u = new URL(url);\n return u.host + (u.pathname !== '/' ? u.pathname : '');\n } catch {\n return url;\n }\n}\n\nfunction truncate(s: string, max: number): string {\n return s.length <= max ? s : s.slice(0, max - 1) + '…';\n}\n","import { createCanvas, type SKRSContext2D } from '@napi-rs/canvas';\n\nlet measureCtx: SKRSContext2D | null = null;\n\nfunction ctx(): SKRSContext2D {\n if (!measureCtx) measureCtx = createCanvas(8, 8).getContext('2d');\n return measureCtx;\n}\n\nexport function measureText(text: string, font: string): number {\n const c = ctx();\n c.font = font;\n return c.measureText(text).width;\n}\n\nexport interface WrapResult {\n lines: string[];\n fontPx: number;\n widest: number;\n shrunk: boolean;\n truncated: boolean;\n}\n\n/**\n * Greedy word-wrap with overflow as a first-class fact: try at fontPx; if the text needs\n * more than maxLines, shrink once to minFontPx; if it still overflows, truncate the last\n * line with an ellipsis AND report it — never silently clip.\n */\nexport function wrapText(\n text: string,\n fontFor: (px: number) => string,\n maxWidth: number,\n fontPx: number,\n minFontPx: number,\n maxLines: number,\n): WrapResult {\n let attempt = wrapAt(text, fontFor(fontPx), maxWidth);\n if (attempt.length <= maxLines) {\n return { lines: attempt, fontPx, widest: widestOf(attempt, fontFor(fontPx)), shrunk: false, truncated: false };\n }\n attempt = wrapAt(text, fontFor(minFontPx), maxWidth);\n if (attempt.length <= maxLines) {\n return { lines: attempt, fontPx: minFontPx, widest: widestOf(attempt, fontFor(minFontPx)), shrunk: true, truncated: false };\n }\n const kept = attempt.slice(0, maxLines);\n let last = kept[maxLines - 1]!;\n const font = fontFor(minFontPx);\n while (last.length > 1 && measureText(last + '…', font) > maxWidth) {\n last = last.slice(0, -1).trimEnd();\n }\n kept[maxLines - 1] = last + '…';\n return { lines: kept, fontPx: minFontPx, widest: widestOf(kept, font), shrunk: true, truncated: true };\n}\n\nfunction wrapAt(text: string, font: string, maxWidth: number): string[] {\n const words = text.split(/\\s+/).filter(Boolean);\n const lines: string[] = [];\n let line = '';\n for (const word of words) {\n const candidate = line ? line + ' ' + word : word;\n if (line && measureText(candidate, font) > maxWidth) {\n lines.push(line);\n line = word;\n } else {\n line = candidate;\n }\n }\n if (line) lines.push(line);\n return lines.length > 0 ? lines : [''];\n}\n\nfunction widestOf(lines: string[], font: string): number {\n return Math.max(...lines.map((l) => measureText(l, font)));\n}\n\n/** Rounded-rect path helper shared by overlay drawing. */\nexport function roundRect(c: SKRSContext2D, x: number, y: number, w: number, h: number, r: number): void {\n const rr = Math.min(r, w / 2, h / 2);\n c.beginPath();\n c.moveTo(x + rr, y);\n c.arcTo(x + w, y, x + w, y + h, rr);\n c.arcTo(x + w, y + h, x, y + h, rr);\n c.arcTo(x, y + h, x, y, rr);\n c.arcTo(x, y, x + w, y, rr);\n c.closePath();\n}\n","import type { CameraKeyframe, CaptionOverlay, ComposeDiagnostics, OutputProfile, OverlayEntry, StepMapEntry } from '../types.js';\nimport { stageContent } from '../types.js';\nimport type { EventLog } from '../../capture/events.js';\nimport type { ResolvedTheme } from '../../theme/index.js';\nimport type { KindProfile } from '../kinds.js';\nimport { writeCaption, type StepTexts } from '../captions.js';\nimport { eventByStepRef } from '../timeline/pacing.js';\nimport { wrapText, measureText } from './text.js';\nimport { sampleCamera } from '../camera/interpolate.js';\nimport { projectRect, type CameraPlane, type Rect } from '../../shared/geometry.js';\n\nconst CARD_PAD_X = 26;\nconst CARD_PAD_Y = 16;\nconst BADGE_GAP = 14;\nconst CARD_BOTTOM_MARGIN = 44;\nconst CHAPTER_LABEL_MS = 1800;\n/** Adjacent captions overlap by this much and cross-dissolve (fade handles the blend). */\nconst CAPTION_CROSSFADE_MS = 240;\n\nfunction overlaps(a: Rect, b: Rect): boolean {\n return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;\n}\n\nexport function buildOverlays(\n steps: StepMapEntry[],\n log: EventLog,\n theme: ResolvedTheme,\n profile: OutputProfile,\n title: string,\n subtitle: string,\n titleCardEndMs: number,\n diagnostics: ComposeDiagnostics,\n kind: KindProfile,\n sceneTitles?: Map<string, string>,\n camera?: CameraKeyframe[],\n specTexts?: Map<string, StepTexts>,\n): OverlayEntry[] {\n const overlays: OverlayEntry[] = [];\n overlays.push({ kind: 'titleCard', cardId: 'title', title, subtitle, tStart: 0, tEnd: titleCardEndMs });\n overlays.push({ kind: 'dip', tStart: titleCardEndMs, tEnd: titleCardEndMs + 400 });\n\n const events = eventByStepRef(log);\n const captioned = steps.filter((s) => {\n const e = events.get(s.stepRef);\n return e && writeCaption(e, specTexts?.get(s.stepRef)) !== null;\n });\n const total = captioned.length;\n let number = 0;\n\n // Chapter labels at each new scene, and an elapsed clock spanning the flow (bug-repro).\n if (kind.chapterCards) {\n const boundaries = sceneBoundaries(steps, sceneTitles);\n let chapter = 0;\n for (const b of boundaries) {\n chapter += 1;\n overlays.push({ kind: 'chapterLabel', title: b.title, ordinal: chapter, tStart: b.outStart, tEnd: b.outStart + CHAPTER_LABEL_MS });\n }\n }\n if (kind.elapsedClock) {\n const firstBeat = captioned[0]?.outBeat ?? titleCardEndMs;\n const last = steps[steps.length - 1];\n overlays.push({ kind: 'elapsedClock', tStart: titleCardEndMs, tEnd: last ? last.outEnd : titleCardEndMs, zeroAtMs: firstBeat });\n }\n\n // `captions: off` renders no caption cards (used for the voice-only cut); the\n // spoken narration still comes from the same text, derived separately in compose.\n for (let i = 0; theme.captionPosition !== 'off' && i < captioned.length; i++) {\n const step = captioned[i]!;\n const event = events.get(step.stepRef)!;\n const base = writeCaption(event, specTexts?.get(step.stepRef))!;\n number += 1;\n const text = kind.captionStyle === 'factual' ? `Step ${number} — ${lowerFirst(base)}` : base;\n\n const fontFor = (px: number) => `${px}px Inter Medium`;\n const showBadge = kind.numberedCaptions && kind.captionStyle !== 'factual';\n const badgeFontPx = 15;\n const badgeText = `${number}/${total}`;\n const badgeW = showBadge ? Math.ceil(measureText(badgeText, `600 ${badgeFontPx}px Inter SemiBold`)) + 20 : 0;\n const badgeGap = showBadge ? BADGE_GAP : 0;\n const maxTextWidth = Math.min(profile.captionMaxWidth, profile.width - 2 * profile.safeArea.left) - CARD_PAD_X * 2 - badgeW - badgeGap;\n\n const wrap = wrapText(text, fontFor, maxTextWidth, theme.captionFontPx, theme.captionMinFontPx, theme.captionMaxLines);\n if (wrap.truncated) diagnostics.overflows.push({ stepRef: step.stepRef, text, action: 'truncated' });\n else if (wrap.shrunk) diagnostics.overflows.push({ stepRef: step.stepRef, text, action: 'shrunk' });\n\n const lineH = Math.round(wrap.fontPx * 1.35);\n const cardW = CARD_PAD_X * 2 + badgeW + badgeGap + Math.ceil(wrap.widest);\n const cardH = CARD_PAD_Y * 2 + wrap.lines.length * lineH;\n const x = (profile.width - cardW) / 2;\n let y =\n theme.captionPosition === 'bottom'\n ? profile.height - CARD_BOTTOM_MARGIN - cardH\n : profile.safeArea.top;\n\n // Collision flip: if the framed subject sits under the caption during the hold, move the\n // caption to the top rather than covering the very thing the step is about.\n if (camera && theme.captionPosition === 'bottom') {\n const rect = step.focusRectVp ?? step.targetRectVp;\n if (rect) {\n const content = stageContent(profile);\n const capPlane: CameraPlane = { vpW: log.meta.viewport.w, vpH: log.meta.viewport.h, outW: content.w, outH: content.h };\n const cam = sampleCamera(camera, Math.min(step.outBeat + 250, step.outEnd));\n const proj = projectRect(rect, cam, capPlane);\n const projFrame: Rect = { x: proj.x + content.x, y: proj.y + content.y, w: proj.w, h: proj.h };\n const capBox: Rect = { x, y, w: cardW, h: cardH };\n if (overlaps(projFrame, capBox)) y = profile.safeArea.top;\n }\n }\n\n // Caption runs slightly INTO the next caption's window so adjacent captions cross-dissolve\n // instead of blinking out to an empty band at every step boundary.\n const next = captioned[i + 1];\n const tEnd = next ? Math.min(step.outEnd, next.outStart + CAPTION_CROSSFADE_MS) : step.outEnd;\n\n const overlay: CaptionOverlay = {\n kind: 'caption',\n stepRef: step.stepRef,\n ordinal: number,\n totalSteps: total,\n showBadge,\n text,\n lines: wrap.lines,\n fontPx: wrap.fontPx,\n box: { x, y, w: cardW, h: cardH },\n tStart: step.outStart,\n tEnd,\n shrunk: wrap.shrunk,\n truncated: wrap.truncated,\n };\n overlays.push(overlay);\n }\n return overlays;\n}\n\n/** First step of each scene, with a human title, for chapter labels. The spec's own\n * `scene.title` wins; deriving from the kebab-case id is only the fallback. */\nfunction sceneBoundaries(\n steps: StepMapEntry[],\n sceneTitles?: Map<string, string>,\n): { title: string; outStart: number }[] {\n const out: { title: string; outStart: number }[] = [];\n let lastScene = '';\n for (const s of steps) {\n if (s.sceneId !== lastScene) {\n lastScene = s.sceneId;\n out.push({ title: sceneTitles?.get(s.sceneId) ?? titleFromSceneId(s.sceneId), outStart: s.outStart });\n }\n }\n return out;\n}\n\nfunction titleFromSceneId(id: string): string {\n const t = id.replace(/-/g, ' ');\n return t.charAt(0).toUpperCase() + t.slice(1);\n}\n\nfunction lowerFirst(s: string): string {\n if (s.length > 1 && s[1] === s[1]!.toUpperCase() && /[A-Z]/.test(s[1]!)) return s;\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n","import { createCanvas, type Canvas, type SKRSContext2D } from '@napi-rs/canvas';\nimport type { BundleData } from '../../bundle/types.js';\nimport type { ComposeManifest, TitleCardOverlay, StepMapEntry } from '../types.js';\nimport { stageContent } from '../types.js';\nimport { sampleSource } from '../timeline/pacing.js';\nimport { sampleCamera } from '../camera/interpolate.js';\nimport { sampleCursor, type CursorPlan } from '../cursor/path.js';\nimport { drawCursor, type CursorGlyph } from '../cursor/render.js';\nimport { drawOverlays, drawTitleCard, drawFailureCard } from '../overlays/draw.js';\nimport { roundRect } from '../overlays/text.js';\nimport { visibleRect, projectPoint, projectRect, clamp, type CameraPlane, type Rect } from '../../shared/geometry.js';\nimport { FrameStore } from './frameStore.js';\nimport { Encoder } from './encoder.js';\nimport { registerFonts } from '../../theme/index.js';\nimport { log } from '../../shared/log.js';\n\nconst SPOTLIGHT_KINDS = new Set(['click', 'dblclick', 'select']);\nconst SPOTLIGHT_LEAD_MS = 200;\nconst SPOTLIGHT_TAIL_MS = 650;\nconst SPOTLIGHT_MAX_DIM = 0.34;\n\n/** Render the full output from a bundle + compose manifest. Pure playback of the plan. */\nexport async function renderVideo(\n bundle: BundleData,\n manifest: ComposeManifest,\n outPath: string,\n): Promise<void> {\n registerFonts();\n const { profile, theme } = manifest;\n const { width, height, fps } = profile;\n // All camera math runs in stage-content space (the same space the planner and verifier use);\n // the renderer's only extra job is translating that space onto the frame at `content.x/y`.\n const content = stageContent(profile);\n const plane: CameraPlane = {\n vpW: manifest.viewport.w,\n vpH: manifest.viewport.h,\n outW: content.w,\n outH: content.h,\n };\n const frameScale = bundle.manifest.frameW / manifest.viewport.w;\n\n const store = new FrameStore(bundle);\n const encoder = new Encoder(outPath, width, height, fps);\n const canvas = createCanvas(width, height);\n const ctx = canvas.getContext('2d');\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = 'high';\n // Offscreen scratch for the spotlight (dim layer with a feathered punch-out).\n const spotCanvas = createCanvas(content.w, content.h);\n const spotCtx = spotCanvas.getContext('2d');\n\n const cursorPlan: CursorPlan = {\n segments: manifest.cursor,\n ripples: manifest.ripples,\n restStart:\n manifest.cursor.length > 0\n ? manifest.cursor[0]!.path[0]!\n : { x: manifest.viewport.w / 2, y: manifest.viewport.h * 0.6 },\n };\n const cards = new Map(\n manifest.overlays\n .filter((o): o is TitleCardOverlay => o.kind === 'titleCard')\n .map((c) => [c.cardId, c]),\n );\n const transitions = manifest.transitions ?? [];\n const spotlightSteps = manifest.steps.filter(\n (s) => SPOTLIGHT_KINDS.has(s.kind) && (s.focusRectVp ?? s.targetRectVp),\n );\n\n const start = Date.now();\n for (let i = 0; i < manifest.totalFrames; i++) {\n const tOut = (i * 1000) / fps;\n const { srcAt, segment } = sampleSource(manifest.segments, tOut);\n\n if (srcAt === null) {\n const failCard =\n segment.kind === 'card' && segment.cardId === 'failure'\n ? manifest.overlays.find((o) => o.kind === 'failureCard')\n : undefined;\n const card = segment.kind === 'card' ? cards.get(segment.cardId) : undefined;\n if (failCard && failCard.kind === 'failureCard') drawFailureCard(ctx, failCard, tOut, theme, profile);\n else if (card) drawTitleCard(ctx, card, tOut, theme, profile);\n else {\n ctx.fillStyle = theme.bg;\n ctx.fillRect(0, 0, width, height);\n }\n } else {\n const cam = sampleCamera(manifest.camera, tOut);\n const vis = visibleRect(cam, plane);\n\n // ---- the stage: matte background + card (chrome bar + footage) ----\n paintStageBackdrop(ctx, profile, theme);\n ctx.save();\n if (profile.stage) {\n paintStageCard(ctx, profile, theme, bundle.manifest.appUrl);\n roundRect(ctx, content.x, content.y, content.w, content.h, 0); // content area (card carries the radius)\n ctx.clip();\n }\n\n // ---- footage: frame blending kills 20→30fps judder during real motion ----\n const drawSrc = (img: Canvas, alpha: number) => {\n ctx.globalAlpha = alpha;\n ctx.drawImage(\n img,\n vis.x * frameScale, vis.y * frameScale, vis.w * frameScale, vis.h * frameScale,\n content.x, content.y, content.w, content.h,\n );\n ctx.globalAlpha = 1;\n };\n const pair = await store.framePairForTime(srcAt);\n // Blend only inside `source` segments (real motion): blending across a freeze would ghost\n // the NEXT action into a deliberate hold.\n if (segment.kind === 'source' && pair.b && pair.mix > 0.12 && pair.gapMs < 400) {\n drawSrc(pair.a, 1);\n drawSrc(pair.b, pair.mix);\n } else {\n drawSrc(pair.a, 1);\n }\n\n // ---- scene-boundary cross-dissolve: old footage fades into the new scene ----\n const tr = transitions.find((w) => tOut >= w.tStart && tOut <= w.tEnd);\n if (tr) {\n const u = clamp((tOut - tr.tStart) / Math.max(1, tr.tEnd - tr.tStart), 0, 1);\n if (u < 1) {\n const from = await store.frameForTime(tr.srcFrom);\n drawSrc(from, 1 - u);\n }\n }\n\n // ---- click spotlight: dim the surroundings, feather-punch the target ----\n const spot = activeSpotlight(spotlightSteps, tOut);\n if (spot) {\n const rect = spot.step.focusRectVp ?? spot.step.targetRectVp!;\n const proj = projectRect(rect, cam, plane);\n drawSpotlight(spotCtx, content, proj, spot.alpha);\n ctx.drawImage(spotCanvas, content.x, content.y);\n }\n\n // Cursor + ripples live on the source plane; project through the camera, then translate\n // into frame space by the stage origin.\n const cursorVp = sampleCursor(cursorPlan, tOut);\n const cursorOut = projectPoint(cursorVp, cam, plane);\n const rippleCenters = manifest.ripples.map((r) => {\n const p = projectPoint({ x: r.x, y: r.y }, cam, plane);\n return { x: p.x + content.x, y: p.y + content.y };\n });\n const glyph = cursorGlyphAt(manifest.steps, tOut);\n drawCursor(\n ctx,\n { x: cursorOut.x + content.x, y: cursorOut.y + content.y },\n cam.zoom,\n tOut,\n manifest.ripples,\n rippleCenters,\n theme,\n plane.outW / plane.vpW,\n glyph,\n );\n ctx.restore();\n }\n\n drawOverlays(ctx, manifest.overlays, tOut, theme, profile);\n await encoder.write(Buffer.from(ctx.getImageData(0, 0, width, height).data.buffer));\n\n if (i > 0 && i % 300 === 0) {\n const fpsNow = i / ((Date.now() - start) / 1000);\n log.debug(`rendered ${i}/${manifest.totalFrames} frames (${fpsNow.toFixed(0)} fps)`);\n }\n }\n await encoder.finish();\n const elapsed = (Date.now() - start) / 1000;\n log.ok(\n `rendered ${manifest.totalFrames} frames in ${elapsed.toFixed(1)}s (${(manifest.totalFrames / elapsed).toFixed(0)} fps) → ${outPath}`,\n );\n}\n\n/** Soft vertical gradient behind the stage, derived from the theme. */\nfunction paintStageBackdrop(ctx: SKRSContext2D, profile: { width: number; height: number }, theme: { bg: string; bgSubtle: string }): void {\n const g = ctx.createLinearGradient(0, 0, 0, profile.height);\n g.addColorStop(0, theme.bgSubtle);\n g.addColorStop(1, theme.bg);\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, profile.width, profile.height);\n}\n\n/** The card: shadow, rounded body, browser-chrome bar (traffic dots + URL pill). */\nfunction paintStageCard(\n ctx: SKRSContext2D,\n profile: { stage?: { content: Rect; chromeH: number; radius: number }; width: number },\n theme: { surface: string; onSurfaceDim: string },\n appUrl: string,\n): void {\n const s = profile.stage!;\n const c = s.content;\n const cardX = c.x;\n const cardY = c.y - s.chromeH;\n const cardW = c.w;\n const cardH = c.h + s.chromeH;\n\n ctx.save();\n ctx.shadowColor = 'rgba(0,0,0,0.45)';\n ctx.shadowBlur = 42;\n ctx.shadowOffsetY = 14;\n ctx.fillStyle = '#20242e';\n roundRect(ctx, cardX, cardY, cardW, cardH, s.radius);\n ctx.fill();\n ctx.restore();\n\n if (s.chromeH > 0) {\n // Traffic dots\n const dotY = cardY + s.chromeH / 2;\n const dotR = Math.max(5, Math.round(s.chromeH * 0.14));\n const colors = ['#ff5f57', '#febc2e', '#28c840'];\n colors.forEach((col, i) => {\n ctx.fillStyle = col;\n ctx.beginPath();\n ctx.arc(cardX + 24 + i * (dotR * 2 + 9), dotY, dotR, 0, Math.PI * 2);\n ctx.fill();\n });\n // URL pill\n const url = displayUrl(appUrl);\n const pillH = Math.round(s.chromeH * 0.62);\n ctx.font = `500 ${Math.round(pillH * 0.52)}px Inter Medium`;\n const textW = ctx.measureText(url).width;\n const pillW = Math.min(cardW * 0.5, textW + 36);\n const pillX = cardX + (cardW - pillW) / 2;\n const pillY = cardY + (s.chromeH - pillH) / 2;\n ctx.fillStyle = 'rgba(255,255,255,0.08)';\n roundRect(ctx, pillX, pillY, pillW, pillH, pillH / 2);\n ctx.fill();\n ctx.fillStyle = 'rgba(255,255,255,0.55)';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(url, pillX + pillW / 2, pillY + pillH / 2 + 1, pillW - 24);\n }\n}\n\nfunction displayUrl(appUrl: string): string {\n try {\n const u = new URL(appUrl);\n return u.host + (u.pathname !== '/' ? u.pathname : '');\n } catch {\n return appUrl;\n }\n}\n\n/** Which spotlight (if any) is active at tOut, with its ramped alpha. */\nfunction activeSpotlight(\n steps: StepMapEntry[],\n tOut: number,\n): { step: StepMapEntry; alpha: number } | null {\n for (const step of steps) {\n const from = step.outBeat - SPOTLIGHT_LEAD_MS;\n const to = step.outBeat + SPOTLIGHT_TAIL_MS;\n if (tOut < from || tOut > to) continue;\n const rampIn = clamp((tOut - from) / 180, 0, 1);\n const rampOut = clamp((to - tOut) / 250, 0, 1);\n return { step, alpha: SPOTLIGHT_MAX_DIM * Math.min(rampIn, rampOut) };\n }\n return null;\n}\n\n/** Dim layer with a feathered punch-out around the target, built on the scratch canvas. */\nfunction drawSpotlight(sctx: SKRSContext2D, content: Rect, proj: Rect, alpha: number): void {\n sctx.clearRect(0, 0, content.w, content.h);\n sctx.fillStyle = `rgba(6,8,14,${alpha.toFixed(3)})`;\n sctx.fillRect(0, 0, content.w, content.h);\n const pad = 14;\n sctx.save();\n sctx.globalCompositeOperation = 'destination-out';\n sctx.shadowColor = '#ffffff';\n sctx.shadowBlur = 30;\n sctx.fillStyle = '#ffffff';\n roundRect(sctx, proj.x - pad, proj.y - pad, proj.w + pad * 2, proj.h + pad * 2, 10);\n sctx.fill();\n sctx.restore();\n}\n\n/** Glyph for the active step: I-beam while typing, arrow otherwise. */\nfunction cursorGlyphAt(steps: StepMapEntry[], tOut: number): CursorGlyph {\n for (const s of steps) {\n if (s.kind === 'type' && tOut >= s.outStart && tOut <= s.outEnd) return 'ibeam';\n }\n return 'arrow';\n}\n","import type { SKRSContext2D } from '@napi-rs/canvas';\nimport type { Point } from '../../shared/geometry.js';\nimport type { ClickRipple } from '../types.js';\nimport type { ResolvedTheme } from '../../theme/index.js';\n\nconst RIPPLE_MS = 350;\nconst PRESS_DOWN_MS = 90;\nconst PRESS_UP_MS = 120;\n\nexport type CursorGlyph = 'arrow' | 'ibeam';\n\n/** Draw the vector cursor at an output-space point.\n * `baseScale` (output px per viewport px) keeps the cursor proportioned to the UI it points\n * at — without it the cursor renders 1.5× too small against upscaled content. */\nexport function drawCursor(\n ctx: SKRSContext2D,\n p: Point,\n zoom: number,\n tOut: number,\n ripples: ClickRipple[],\n rippleCenters: Point[],\n theme: ResolvedTheme,\n baseScale = 1,\n glyph: CursorGlyph = 'arrow',\n): void {\n // Press animation: scale dips to 0.85 around each click beat.\n let scale = 1;\n for (const r of ripples) {\n const dt = tOut - r.tOut;\n if (dt >= -PRESS_DOWN_MS && dt < 0) scale = 1 - 0.15 * (1 + dt / PRESS_DOWN_MS);\n else if (dt >= 0 && dt <= PRESS_UP_MS) scale = 0.85 + 0.15 * (dt / PRESS_UP_MS);\n }\n\n // Expanding ring at click points (drawn under the cursor).\n for (let i = 0; i < ripples.length; i++) {\n const r = ripples[i]!;\n const dt = tOut - r.tOut;\n if (dt < 0 || dt > RIPPLE_MS) continue;\n const u = dt / RIPPLE_MS;\n const c = rippleCenters[i]!;\n ctx.save();\n ctx.beginPath();\n ctx.arc(c.x, c.y, (6 + 42 * easeOut(u)) * baseScale, 0, Math.PI * 2);\n ctx.strokeStyle = theme.accent;\n ctx.globalAlpha = 0.6 * (1 - u);\n ctx.lineWidth = 3.5 * baseScale * (1 - u * 0.5);\n ctx.stroke();\n ctx.restore();\n }\n\n const size = 24 * baseScale * (1 + 0.15 * (zoom - 1)) * scale;\n ctx.save();\n ctx.translate(p.x, p.y);\n ctx.scale(size / 24, size / 24);\n ctx.shadowColor = 'rgba(0,0,0,0.35)';\n ctx.shadowBlur = 5;\n ctx.shadowOffsetY = 1.5;\n if (glyph === 'ibeam') {\n // I-beam (text) cursor, hotspot at the beam center.\n ctx.beginPath();\n ctx.moveTo(-4, -9);\n ctx.lineTo(4, -9);\n ctx.moveTo(0, -9);\n ctx.lineTo(0, 9);\n ctx.moveTo(-4, 9);\n ctx.lineTo(4, 9);\n ctx.lineWidth = 2.4;\n ctx.strokeStyle = '#ffffff';\n ctx.stroke();\n ctx.shadowColor = 'transparent';\n ctx.lineWidth = 1;\n ctx.strokeStyle = 'rgba(20,24,34,0.9)';\n ctx.stroke();\n } else {\n // Arrow pointer path (24px design grid, hotspot at 0,0)\n ctx.beginPath();\n ctx.moveTo(0, 0);\n ctx.lineTo(0, 17.5);\n ctx.lineTo(4.2, 13.6);\n ctx.lineTo(7.4, 20.6);\n ctx.lineTo(10.3, 19.2);\n ctx.lineTo(7.2, 12.4);\n ctx.lineTo(12.8, 12.2);\n ctx.closePath();\n ctx.fillStyle = '#ffffff';\n ctx.fill();\n ctx.shadowColor = 'transparent';\n ctx.lineWidth = 1.4;\n ctx.strokeStyle = 'rgba(20,24,34,0.9)';\n ctx.stroke();\n }\n ctx.restore();\n}\n\nfunction easeOut(u: number): number {\n return 1 - (1 - u) * (1 - u);\n}\n","import type { SKRSContext2D } from '@napi-rs/canvas';\nimport type { CaptionOverlay, OutputProfile, OverlayEntry, TitleCardOverlay } from '../types.js';\nimport type { ResolvedTheme } from '../../theme/index.js';\nimport { roundRect, measureText } from './text.js';\nimport { clamp } from '../../shared/geometry.js';\n\nconst FADE_MS = 200;\nconst SCRIM_H = 210;\n\nexport function drawOverlays(\n ctx: SKRSContext2D,\n overlays: OverlayEntry[],\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n // Bottom gradient scrim behind the caption band, drawn ONCE at the strongest active caption's\n // alpha (overlapping cross-fading captions must not double-darken it). Keeps caption text off\n // raw UI pixels regardless of what the app renders down there.\n const bottomCaptions = overlays.filter(\n (o): o is CaptionOverlay =>\n o.kind === 'caption' && tOut >= o.tStart && tOut <= o.tEnd && o.box.y > profile.height / 2,\n );\n if (bottomCaptions.length > 0) {\n const a = Math.max(...bottomCaptions.map((o) => captionAlpha(o, tOut)));\n if (a > 0) {\n const g = ctx.createLinearGradient(0, profile.height - SCRIM_H, 0, profile.height);\n g.addColorStop(0, 'rgba(8,10,16,0)');\n g.addColorStop(1, `rgba(8,10,16,${(0.55 * a).toFixed(3)})`);\n ctx.fillStyle = g;\n ctx.fillRect(0, profile.height - SCRIM_H, profile.width, SCRIM_H);\n }\n }\n\n for (const o of overlays) {\n if (tOut < o.tStart || tOut > o.tEnd) continue;\n switch (o.kind) {\n case 'caption':\n drawCaption(ctx, o, tOut, theme);\n break;\n case 'dip': {\n // 'in': fade from theme bg into footage (post-title). 'out': fade footage into the bg\n // (pre-end-card), so the closing card doesn't hard-cut in.\n const u = (tOut - o.tStart) / Math.max(1, o.tEnd - o.tStart);\n ctx.save();\n ctx.globalAlpha = o.direction === 'out' ? u : 1 - u;\n ctx.fillStyle = theme.bg;\n ctx.fillRect(0, 0, profile.width, profile.height);\n ctx.restore();\n break;\n }\n case 'elapsedClock':\n drawElapsedClock(ctx, o.zeroAtMs, tOut, theme, profile);\n break;\n case 'chapterLabel':\n drawChapterLabel(ctx, o, tOut, theme, profile);\n break;\n case 'titleCard':\n case 'failureCard':\n // Painted by the renderer as a full-frame card (not an overlay on footage).\n break;\n }\n }\n}\n\nfunction drawElapsedClock(\n ctx: SKRSContext2D,\n zeroAtMs: number,\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n const ms = Math.max(0, tOut - zeroAtMs);\n const s = Math.floor(ms / 1000);\n const label = `${String(Math.floor(s / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}.${String(Math.floor((ms % 1000) / 100))}`;\n const font = '600 26px Inter SemiBold';\n ctx.save();\n ctx.font = font;\n const textW = ctx.measureText(label).width;\n const padX = 16;\n const w = textW + padX * 2 + 30;\n const h = 44;\n const x = profile.width - profile.safeArea.right - w;\n const y = profile.safeArea.top;\n ctx.fillStyle = 'rgba(18,22,31,0.82)';\n roundRect(ctx, x, y, w, h, 10);\n ctx.fill();\n // A small \"recording\" dot.\n ctx.fillStyle = '#ef4444';\n ctx.beginPath();\n ctx.arc(x + padX + 6, y + h / 2, 6, 0, Math.PI * 2);\n ctx.fill();\n ctx.fillStyle = '#ffffff';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.font = font;\n ctx.fillText(label, x + padX + 24, y + h / 2 + 1);\n ctx.restore();\n}\n\nfunction drawChapterLabel(\n ctx: SKRSContext2D,\n o: { title: string; ordinal: number; tStart: number; tEnd: number },\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n const alpha = clamp(Math.min((tOut - o.tStart) / 260, (o.tEnd - tOut) / 320), 0, 1);\n if (alpha <= 0) return;\n ctx.save();\n ctx.globalAlpha = alpha;\n const font = '700 30px Inter Bold';\n ctx.font = font;\n const textW = ctx.measureText(o.title).width;\n const barW = textW + 96;\n const barH = 56;\n const x = (profile.width - barW) / 2;\n // Below the stage's chrome bar (never over the URL pill); safe-area top otherwise.\n const y = profile.stage ? profile.stage.content.y + 14 : profile.safeArea.top + 8;\n ctx.fillStyle = theme.accent;\n roundRect(ctx, x, y, barW, barH, 12);\n ctx.fill();\n ctx.fillStyle = '#ffffff';\n ctx.font = '600 16px Inter SemiBold';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(String(o.ordinal), x + 22, y + barH / 2 + 1);\n ctx.font = font;\n ctx.fillText(o.title, x + 48, y + barH / 2 + 1);\n ctx.restore();\n}\n\nfunction captionAlpha(o: CaptionOverlay, tOut: number): number {\n return clamp(Math.min((tOut - o.tStart) / FADE_MS, (o.tEnd - tOut) / FADE_MS), 0, 1);\n}\n\nfunction drawCaption(ctx: SKRSContext2D, o: CaptionOverlay, tOut: number, theme: ResolvedTheme): void {\n const alpha = captionAlpha(o, tOut);\n if (alpha <= 0) return;\n ctx.save();\n ctx.globalAlpha = alpha;\n\n // Card\n ctx.shadowColor = 'rgba(0,0,0,0.30)';\n ctx.shadowBlur = 18;\n ctx.shadowOffsetY = 4;\n ctx.fillStyle = theme.surface;\n roundRect(ctx, o.box.x, o.box.y, o.box.w, o.box.h, theme.radius);\n ctx.fill();\n ctx.shadowColor = 'transparent';\n\n // Step badge chip (omitted for styles that don't number captions)\n let badgeW = 0;\n const bx = o.box.x + 26;\n if (o.showBadge) {\n const badgeText = `${o.ordinal}/${o.totalSteps}`;\n const badgeFont = `600 15px Inter SemiBold`;\n badgeW = Math.ceil(measureText(badgeText, badgeFont)) + 20;\n const badgeH = 26;\n const by = o.box.y + o.box.h / 2 - badgeH / 2;\n ctx.fillStyle = theme.accent;\n roundRect(ctx, bx, by, badgeW, badgeH, 13);\n ctx.fill();\n ctx.fillStyle = '#ffffff';\n ctx.font = badgeFont;\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'center';\n ctx.fillText(badgeText, bx + badgeW / 2, by + badgeH / 2 + 1);\n }\n\n // Caption text\n const lineH = Math.round(o.fontPx * 1.35);\n const textX = o.showBadge ? bx + badgeW + 14 : bx;\n const textTop = o.box.y + (o.box.h - o.lines.length * lineH) / 2;\n ctx.fillStyle = theme.onSurface;\n ctx.font = `${o.fontPx}px Inter Medium`;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n o.lines.forEach((line, i) => {\n ctx.fillText(line, textX, textTop + i * lineH + lineH / 2 + 1);\n });\n ctx.restore();\n}\n\n/** The failure clip's closing card: what step broke and why, in evidence red. */\nexport function drawFailureCard(\n ctx: SKRSContext2D,\n card: { stepRef: string; message: string; tStart: number },\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n const { width, height } = profile;\n const g = ctx.createLinearGradient(0, 0, 0, height);\n g.addColorStop(0, '#1c1114');\n g.addColorStop(1, '#12090b');\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, width, height);\n\n const t = tOut - card.tStart;\n const a = clamp(t / 300, 0, 1);\n ctx.save();\n ctx.globalAlpha = a;\n\n ctx.fillStyle = '#ef4444';\n roundRect(ctx, width / 2 - 32, height / 2 - 150, 64, 8, 4);\n ctx.fill();\n\n ctx.fillStyle = '#ffffff';\n ctx.font = `52px Inter Bold`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText('Flow failed', width / 2, height / 2 - 70);\n\n ctx.fillStyle = '#fca5a5';\n ctx.font = `600 30px Inter SemiBold`;\n ctx.fillText(`at step ${card.stepRef}`, width / 2, height / 2 - 12);\n\n // Error message, wrapped to a readable measure.\n ctx.fillStyle = 'rgba(255,255,255,0.75)';\n ctx.font = `24px Inter`;\n const maxW = Math.min(1200, width - 200);\n const words = card.message.replace(/\\s+/g, ' ').split(' ');\n const lines: string[] = [];\n let line = '';\n for (const w of words) {\n const probe = line ? `${line} ${w}` : w;\n if (ctx.measureText(probe).width > maxW && line) {\n lines.push(line);\n line = w;\n if (lines.length >= 3) break;\n } else line = probe;\n }\n if (lines.length < 3 && line) lines.push(line);\n else if (line && lines.length >= 3) lines[2] = `${lines[2]!.slice(0, -1)}…`;\n lines.forEach((l, i) => ctx.fillText(l, width / 2, height / 2 + 48 + i * 36));\n ctx.restore();\n}\n\nexport function drawTitleCard(\n ctx: SKRSContext2D,\n card: TitleCardOverlay,\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n const { width, height } = profile;\n // Ground with the same gradient the stage uses, so the dip into footage feels continuous.\n const g = ctx.createLinearGradient(0, 0, 0, height);\n g.addColorStop(0, theme.bgSubtle);\n g.addColorStop(1, theme.bg);\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, width, height);\n\n // Staggered entrance: bar → title → subtitle, each rising 16px as it fades in. A group fade\n // with zero motion reads as a slide; a 200ms stagger reads as designed.\n const t = tOut - card.tStart;\n const enter = (delay: number) => {\n const u = clamp((t - delay) / 380, 0, 1);\n const e = 1 - (1 - u) * (1 - u) * (1 - u); // easeOutCubic\n return { alpha: u, rise: 16 * (1 - e) };\n };\n const bar = enter(0);\n const title = enter(130);\n const sub = enter(240);\n\n ctx.save();\n ctx.globalAlpha = bar.alpha;\n ctx.fillStyle = theme.accent;\n roundRect(ctx, width / 2 - 32, height / 2 - 110 + bar.rise, 64, 8, 4);\n ctx.fill();\n\n ctx.globalAlpha = title.alpha;\n ctx.fillStyle = '#ffffff';\n ctx.font = `56px Inter Bold`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(card.title, width / 2, height / 2 - 20 + title.rise);\n\n if (card.subtitle) {\n ctx.globalAlpha = sub.alpha;\n ctx.fillStyle = theme.onSurfaceDim;\n ctx.font = `26px Inter`;\n ctx.fillText(card.subtitle, width / 2, height / 2 + 44 + sub.rise);\n }\n ctx.restore();\n}\n","import sharp from 'sharp';\nimport { createCanvas, ImageData, type Canvas } from '@napi-rs/canvas';\nimport type { BundleData } from '../../bundle/types.js';\nimport { frameIndexForTime, framePath } from '../../bundle/reader.js';\n\nconst LRU_SIZE = 6;\n\n/**\n * Timestamp-indexed source-frame store with an LRU of decoded frames and one-ahead\n * prefetch. Access during a render is monotonic in time, so a small cache wins.\n */\nexport class FrameStore {\n private cache = new Map<number, Promise<Canvas>>();\n\n constructor(private readonly bundle: BundleData) {}\n\n /** Decoded canvas for the frame that should be on screen at capture-relative tMs. */\n async frameForTime(tMs: number): Promise<Canvas> {\n const idx = frameIndexForTime(this.bundle.frames, tMs);\n const canvas = await this.get(idx);\n // Prefetch the next distinct frame while this one is being drawn.\n if (idx + 1 < this.bundle.frames.length) void this.get(idx + 1);\n return canvas;\n }\n\n /**\n * The frame at tMs plus its successor with a blend factor: the capture is ~20fps but output\n * is 30fps, so nearest-frame playback holds each source frame in a 2-1-2-1 judder pattern.\n * Blending adjacent frames during real motion smooths it without optical flow.\n */\n async framePairForTime(tMs: number): Promise<{ a: Canvas; b: Canvas | null; mix: number; gapMs: number }> {\n const idx = frameIndexForTime(this.bundle.frames, tMs);\n const a = await this.get(idx);\n if (idx + 1 >= this.bundle.frames.length) return { a, b: null, mix: 0, gapMs: Infinity };\n const t0 = this.bundle.frames[idx]!.t;\n const t1 = this.bundle.frames[idx + 1]!.t;\n const gapMs = t1 - t0;\n const mix = gapMs > 0 ? Math.min(1, Math.max(0, (tMs - t0) / gapMs)) : 0;\n const b = await this.get(idx + 1);\n return { a, b, mix, gapMs };\n }\n\n private get(idx: number): Promise<Canvas> {\n const hit = this.cache.get(idx);\n if (hit) {\n // refresh recency\n this.cache.delete(idx);\n this.cache.set(idx, hit);\n return hit;\n }\n const promise = this.decode(idx);\n this.cache.set(idx, promise);\n while (this.cache.size > LRU_SIZE) {\n const oldest = this.cache.keys().next().value as number;\n this.cache.delete(oldest);\n }\n return promise;\n }\n\n private async decode(idx: number): Promise<Canvas> {\n const { data, info } = await sharp(framePath(this.bundle, idx))\n .ensureAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true });\n const canvas = createCanvas(info.width, info.height);\n const ctx = canvas.getContext('2d');\n ctx.putImageData(new ImageData(new Uint8ClampedArray(data.buffer, data.byteOffset, data.byteLength), info.width, info.height), 0, 0);\n return canvas;\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\nimport { once } from 'node:events';\nimport { ffmpegPath } from '../../shared/ffmpeg.js';\n\n/**\n * Streaming H.264 encoder: raw RGBA frames in on stdin, MP4 out. Backpressure is\n * respected — write() resolves only when the pipe can take more.\n */\nexport class Encoder {\n private child: ChildProcess;\n private stderrTail: string[] = [];\n private exit: Promise<number>;\n\n constructor(outPath: string, width: number, height: number, fps: number) {\n this.child = spawn(\n ffmpegPath(),\n [\n '-hide_banner',\n '-loglevel', 'error',\n '-f', 'rawvideo',\n '-pix_fmt', 'rgba',\n '-s', `${width}x${height}`,\n '-r', String(fps),\n '-i', 'pipe:0',\n // A silent AAC track: some players/galleries refuse an audio-less MP4.\n '-f', 'lavfi',\n '-i', 'anullsrc=channel_layout=stereo:sample_rate=44100',\n '-c:v', 'libx264',\n '-preset', 'medium',\n '-crf', '18',\n '-pix_fmt', 'yuv420p',\n '-profile:v', 'high',\n '-c:a', 'aac',\n '-b:a', '96k',\n '-shortest',\n '-movflags', '+faststart',\n '-y',\n outPath,\n ],\n { stdio: ['pipe', 'ignore', 'pipe'] },\n );\n this.child.stderr!.on('data', (d: Buffer) => {\n this.stderrTail.push(d.toString('utf8'));\n if (this.stderrTail.length > 40) this.stderrTail.shift();\n });\n this.exit = new Promise((resolve, reject) => {\n this.child.on('error', reject);\n this.child.on('close', (code) => resolve(code ?? -1));\n });\n }\n\n async write(rgba: Buffer): Promise<void> {\n const stdin = this.child.stdin!;\n if (!stdin.writable) throw new Error(`ffmpeg closed early: ${this.stderrTail.join('')}`);\n if (!stdin.write(rgba)) {\n await once(stdin, 'drain');\n }\n }\n\n async finish(): Promise<void> {\n this.child.stdin!.end();\n const code = await this.exit;\n if (code !== 0) {\n throw new Error(`ffmpeg exited with code ${code}: ${this.stderrTail.join('')}`);\n }\n }\n}\n","import { spawn } from 'node:child_process';\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\n/** Resolve the ffmpeg binary: $PLAYHEAD_FFMPEG override, else the bundled ffmpeg-static build. */\nexport function ffmpegPath(): string {\n if (process.env.PLAYHEAD_FFMPEG) return process.env.PLAYHEAD_FFMPEG;\n const p = require('ffmpeg-static') as string | null;\n if (!p) throw new Error('ffmpeg-static did not provide a binary; set PLAYHEAD_FFMPEG');\n return p;\n}\n\nexport function ffprobePath(): string {\n if (process.env.PLAYHEAD_FFPROBE) return process.env.PLAYHEAD_FFPROBE;\n const mod = require('ffprobe-static') as { path: string };\n return mod.path;\n}\n\nexport interface RunResult {\n code: number;\n stdout: string;\n stderr: string;\n}\n\n/** Run ffmpeg/ffprobe to completion, capturing output. For the streaming encoder see compose/render/encoder.ts. */\nexport function runBinary(bin: string, args: string[], stdin?: Buffer): Promise<RunResult> {\n return new Promise((resolve, reject) => {\n const child = spawn(bin, args, { stdio: ['pipe', 'pipe', 'pipe'] });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n child.stdout.on('data', (d) => out.push(d));\n child.stderr.on('data', (d) => err.push(d));\n child.on('error', reject);\n child.on('close', (code) => {\n resolve({\n code: code ?? -1,\n stdout: Buffer.concat(out).toString('utf8'),\n stderr: Buffer.concat(err).toString('utf8'),\n });\n });\n if (stdin) child.stdin.end(stdin);\n else child.stdin.end();\n });\n}\n\n/** Losslessly concatenate H.264 MP4s (same codec/params) into one file via the concat demuxer. */\nexport async function concatVideos(inputs: string[], outPath: string): Promise<void> {\n const { writeFile, mkdtemp, rm } = await import('node:fs/promises');\n const { join } = await import('node:path');\n const { tmpdir } = await import('node:os');\n const dir = await mkdtemp(join(tmpdir(), 'playhead-concat-'));\n const listPath = join(dir, 'list.txt');\n await writeFile(listPath, inputs.map((p) => `file '${p.replace(/'/g, \"'\\\\''\")}'`).join('\\n'));\n try {\n const res = await runBinary(ffmpegPath(), [\n '-hide_banner', '-loglevel', 'error',\n '-f', 'concat', '-safe', '0',\n '-i', listPath,\n '-c', 'copy',\n '-movflags', '+faststart',\n '-y', outPath,\n ]);\n if (res.code !== 0) throw new Error(`concat failed: ${res.stderr}`);\n } finally {\n await rm(dir, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/** Run ffmpeg, returning raw stdout bytes (for image2pipe extraction). */\nexport function runBinaryRaw(bin: string, args: string[]): Promise<{ code: number; stdout: Buffer; stderr: string }> {\n return new Promise((resolve, reject) => {\n const child = spawn(bin, args, { stdio: ['ignore', 'pipe', 'pipe'] });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n child.stdout.on('data', (d) => out.push(d));\n child.stderr.on('data', (d) => err.push(d));\n child.on('error', reject);\n child.on('close', (code) => {\n resolve({ code: code ?? -1, stdout: Buffer.concat(out), stderr: Buffer.concat(err).toString('utf8') });\n });\n });\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createHash } from 'node:crypto';\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\nconst ffprobePath: string = require('ffprobe-static').path;\nconst exec = promisify(execFile);\n\nexport interface NarrationOptions {\n /** 'say' — macOS built-in (zero deps, Mac-only). 'kokoro' — natural neural voice, offline,\n * cross-platform, via the optional kokoro-js package. */\n provider: 'say' | 'kokoro';\n /** say: a macOS voice name (Samantha). kokoro: a voice id (af_heart, am_michael, …). */\n voice?: string;\n /** say: words per minute. kokoro: playback speed × 100 (100 = 1.0×). */\n rate?: number;\n}\n\nexport interface NarrationLine {\n stepRef: string;\n text: string;\n}\n\nexport interface NarrationClip {\n stepRef: string;\n file: string;\n durationMs: number;\n}\n\n/** A text-to-speech backend: text → an audio file on disk. */\ninterface TtsProvider {\n readonly name: string;\n synth(text: string, outFile: string): Promise<void>;\n}\n\nclass SayProvider implements TtsProvider {\n readonly name = 'say';\n constructor(private voice: string, private rate: number) {}\n async synth(text: string, outFile: string): Promise<void> {\n // Pass the text via a file so em-dashes / quotes / apostrophes survive shell escaping.\n const txt = `${outFile}.txt`;\n await writeFile(txt, text);\n await exec('say', ['-v', this.voice, '-r', String(this.rate), '-f', txt, '-o', outFile]);\n }\n}\n\n/**\n * Kokoro — a natural, offline neural voice (the Kokoro-82M model) via the optional pure-Node\n * `kokoro-js` package. The model (~90MB q8) loads ONCE on the first line and is reused for the\n * rest, so a multi-line narration pays the load cost a single time. Output is WAV.\n *\n * kokoro-js is NOT a hard dependency (it pulls onnxruntime, ~400MB) — it is lazily imported and,\n * if absent, produces an actionable error. On networks that intercept TLS (corporate proxies),\n * set NODE_EXTRA_CA_CERTS so the one-time model download from Hugging Face can verify.\n */\nclass KokoroProvider implements TtsProvider {\n readonly name = 'kokoro';\n private tts: Promise<{ generate: (t: string, o: { voice: string; speed: number }) => Promise<{ save: (p: string) => Promise<void> }> }> | null = null;\n constructor(private voice: string, private speed: number) {}\n\n private load() {\n if (this.tts) return this.tts;\n this.tts = (async () => {\n let mod: { KokoroTTS: { from_pretrained: (id: string, o: object) => Promise<unknown> } };\n try {\n mod = (await import('kokoro-js' as string)) as typeof mod;\n } catch {\n throw new Error(\n \"the 'kokoro' voice needs the optional kokoro-js package — install it with `npm i -g kokoro-js` \" +\n '(or add it to your project). It bundles the neural model runtime (~400MB); the base playhead-cli stays lean.',\n );\n }\n return (await mod.KokoroTTS.from_pretrained('onnx-community/Kokoro-82M-v1.0-ONNX', {\n dtype: 'q8',\n device: 'cpu',\n })) as Awaited<NonNullable<KokoroProvider['tts']>>;\n })();\n return this.tts;\n }\n\n async synth(text: string, outFile: string): Promise<void> {\n const tts = await this.load();\n const audio = await tts.generate(text, { voice: this.voice, speed: this.speed });\n await audio.save(outFile); // WAV\n }\n}\n\nfunction providerFor(opts: NarrationOptions): { provider: TtsProvider; voice: string; rate: number } {\n switch (opts.provider) {\n case 'say': {\n const voice = opts.voice ?? 'Samantha';\n const rate = opts.rate ?? 178;\n return { provider: new SayProvider(voice, rate), voice, rate };\n }\n case 'kokoro': {\n // Two curated voices only — Heart (default) and Michael. Friendly aliases map to the ids.\n const KOKORO_VOICES: Record<string, string> = {\n heart: 'af_heart',\n af_heart: 'af_heart',\n michael: 'am_michael',\n am_michael: 'am_michael',\n };\n const requested = opts.voice ?? 'heart';\n const voice = KOKORO_VOICES[requested];\n if (!voice) throw new Error(`kokoro voice must be 'heart' (default) or 'michael', got '${requested}'`);\n const rate = opts.rate ?? 100; // ×100 → 1.0 playback speed\n return { provider: new KokoroProvider(voice, rate / 100), voice, rate };\n }\n default:\n throw new Error(`unknown TTS provider: ${(opts as { provider: string }).provider}`);\n }\n}\n\nasync function probeDurationMs(file: string): Promise<number> {\n const { stdout } = await exec(ffprobePath, [\n '-v', 'error', '-show_entries', 'format=duration', '-of', 'csv=p=0', file,\n ]);\n return Math.round(parseFloat(stdout.trim()) * 1000);\n}\n\n/**\n * Synthesize one clip per line. Clips are cached by a content hash of\n * (provider, voice, rate, text) so re-renders reuse them — keeping compose offline\n * and deterministic (same text+voice → same audio → same timing).\n */\nexport async function synthesizeNarration(\n lines: NarrationLine[],\n opts: NarrationOptions,\n cacheDir: string,\n): Promise<Map<string, NarrationClip>> {\n await mkdir(cacheDir, { recursive: true });\n const { provider, voice, rate } = providerFor(opts);\n const ext = provider.name === 'kokoro' ? 'wav' : 'aiff';\n const out = new Map<string, NarrationClip>();\n for (const { stepRef, text } of lines) {\n const key = createHash('sha256').update(`${provider.name}|${voice}|${rate}|${text}`).digest('hex').slice(0, 16);\n const file = join(cacheDir, `${key}.${ext}`);\n if (!existsSync(file)) await provider.synth(text, file);\n out.set(stepRef, { stepRef, file, durationMs: await probeDurationMs(file) });\n }\n return out;\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { rename, mkdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createRequire } from 'node:module';\nimport type { StepMapEntry, ClickRipple } from '../compose/types.js';\nimport type { NarrationClip } from './tts.js';\nimport { AUDIO_LEAD_MS } from './timing.js';\n\nconst require = createRequire(import.meta.url);\nconst ffmpegPath: string = require('ffmpeg-static');\nconst exec = promisify(execFile);\n\nexport interface PlacedClip {\n stepRef: string;\n /** Output-clock ms the clip starts playing. */\n tStart: number;\n durMs: number;\n}\n\nexport interface AudioBedOptions {\n /** Narration clips per stepRef (absent = no narration). */\n narration?: Map<string, NarrationClip>;\n /** Click-beat times (output clock) that get a soft synthesized tick. */\n sfxBeats?: ClickRipple[];\n /** User-supplied music bed (no asset is bundled). */\n music?: { file: string; gainDb: number };\n /** Directory for the synthesized click sample (cached). */\n cacheDir: string;\n}\n\n/**\n * Build the full audio track — narration clips at their step starts, click ticks at ripple\n * beats, an optional music bed ducked under narration — normalize loudness (EBU R128, I=-16),\n * and mux it onto the rendered MP4. Returns where each narration clip landed so verification\n * can reason about voice windows.\n */\nexport async function mixAudio(\n videoPath: string,\n steps: StepMapEntry[],\n durationMs: number,\n opts: AudioBedOptions,\n): Promise<PlacedClip[]> {\n const placed = (opts.narration ? steps : [])\n .map((s) => ({ start: Math.round(s.outStart + AUDIO_LEAD_MS), clip: opts.narration!.get(s.stepRef) }))\n .filter((p): p is { start: number; clip: NarrationClip } => p.clip !== undefined);\n const beats = opts.sfxBeats ?? [];\n const hasMusic = !!opts.music;\n if (placed.length === 0 && beats.length === 0 && !hasMusic) return [];\n\n const durSec = (durationMs / 1000).toFixed(3);\n const args = ['-y', '-loglevel', 'error', '-i', videoPath];\n const inputs: string[] = []; // filter labels for the final mix\n const filters: string[] = [];\n let inputIdx = 1;\n\n // Silent full-length base keeps the mix spanning the whole video.\n args.push('-f', 'lavfi', '-t', durSec, '-i', 'anullsrc=r=44100:cl=stereo');\n const baseIdx = inputIdx++;\n inputs.push(`[${baseIdx}]`);\n\n // Narration clips, delayed to their step starts, pre-mixed into one voice bus.\n let voiceBus: string | null = null;\n if (placed.length > 0) {\n const labels: string[] = [];\n placed.forEach((p, i) => {\n args.push('-i', p.clip.file);\n const idx = inputIdx++;\n filters.push(\n `[${idx}]aformat=sample_rates=44100:channel_layouts=stereo,adelay=${p.start}|${p.start}[v${i}]`,\n );\n labels.push(`[v${i}]`);\n });\n filters.push(`${labels.join('')}amix=inputs=${labels.length}:normalize=0:duration=longest[voice]`);\n voiceBus = '[voice]';\n }\n\n // Click SFX: one synthesized sample, split and delayed to each beat.\n if (beats.length > 0) {\n const click = await ensureClickSample(opts.cacheDir);\n args.push('-i', click);\n const idx = inputIdx++;\n const splits = beats.map((_, i) => `[c${i}]`).join('');\n filters.push(`[${idx}]aformat=sample_rates=44100:channel_layouts=stereo,asplit=${beats.length}${splits}`);\n const labels: string[] = [];\n beats.forEach((b, i) => {\n const at = Math.max(0, Math.round(b.tOut));\n filters.push(`[c${i}]adelay=${at}|${at}[ck${i}]`);\n labels.push(`[ck${i}]`);\n });\n filters.push(`${labels.join('')}amix=inputs=${labels.length}:normalize=0:duration=longest[sfx]`);\n inputs.push('[sfx]');\n }\n\n // Music bed: looped to length, faded out, gained down — and DUCKED under narration.\n if (opts.music) {\n args.push('-stream_loop', '-1', '-i', opts.music.file);\n const idx = inputIdx++;\n const fadeStart = Math.max(0, durationMs / 1000 - 1.8).toFixed(2);\n filters.push(\n `[${idx}]aformat=sample_rates=44100:channel_layouts=stereo,atrim=0:${durSec},` +\n `volume=${opts.music.gainDb}dB,afade=t=out:st=${fadeStart}:d=1.8[mraw]`,\n );\n if (voiceBus) {\n // Duplicate the voice bus: one copy keys the compressor, one goes to the mix.\n filters.push(`${voiceBus}asplit=2[vmain][vkey]`);\n filters.push(`[mraw][vkey]sidechaincompress=threshold=0.02:ratio=8:attack=40:release=400[mduck]`);\n inputs.push('[mduck]', '[vmain]');\n voiceBus = null;\n } else {\n inputs.push('[mraw]');\n }\n }\n if (voiceBus) inputs.push(voiceBus);\n\n filters.push(\n `${inputs.join('')}amix=inputs=${inputs.length}:normalize=0:duration=longest,` +\n `loudnorm=I=-16:TP=-1.5:LRA=11[mix]`,\n );\n\n const tmp = videoPath.replace(/\\.mp4$/, '.audio.tmp.mp4');\n args.push(\n '-filter_complex', filters.join(';'),\n '-map', '0:v:0', '-map', '[mix]',\n '-c:v', 'copy', '-c:a', 'aac', '-b:a', '160k',\n '-shortest', '-movflags', '+faststart',\n tmp,\n );\n await exec(ffmpegPath, args, { maxBuffer: 1 << 24 });\n await rename(tmp, videoPath);\n return placed.map((p) => ({ stepRef: p.clip.stepRef, tStart: p.start, durMs: p.clip.durationMs }));\n}\n\n/** Synthesize the click sample once: a soft 2-tone tick with a fast decay (no bundled assets). */\nasync function ensureClickSample(cacheDir: string): Promise<string> {\n await mkdir(cacheDir, { recursive: true });\n const file = join(cacheDir, 'click.wav');\n if (existsSync(file)) return file;\n await exec(ffmpegPath, [\n '-y', '-loglevel', 'error',\n '-f', 'lavfi', '-i', 'sine=frequency=1250:duration=0.05',\n '-f', 'lavfi', '-i', 'sine=frequency=2500:duration=0.03',\n '-filter_complex',\n '[0]volume=0.5[a];[1]volume=0.22[b];[a][b]amix=inputs=2:normalize=0,afade=t=in:d=0.004,afade=t=out:st=0.014:d=0.036,aformat=sample_rates=44100:channel_layouts=stereo',\n file,\n ]);\n return file;\n}\n","import { join } from 'node:path';\nimport { mkdir, writeFile, readFile } from 'node:fs/promises';\nimport type { BundleData } from '../bundle/types.js';\nimport type { ComposeManifest } from '../compose/types.js';\nimport type { CheckResult, Verdict, VerifyContext } from './types.js';\nimport {\n checkActionEffect,\n checkAudio,\n checkCaptions,\n checkCursorOnTarget,\n checkEncode,\n checkFrozenBlank,\n checkMasks,\n checkOutputPixels,\n checkPacing,\n checkTargetInFrame,\n} from './checks.js';\nimport { renderContactSheet } from './contact-sheet.js';\nimport { visionReview } from './vision.js';\nimport { sha256File } from '../bundle/hash.js';\nimport { signVerdict } from './report.js';\nimport { PLAYHEAD_VERSION } from '../shared/version.js';\nimport { log } from '../shared/log.js';\nimport { platform, arch } from 'node:os';\nimport pc from 'picocolors';\n\n/** Bumped whenever a check is added or its semantics change — part of provenance. */\nexport const CHECK_SUITE_VERSION = 'playhead/checks@2';\n\nexport interface VerifyOptions {\n outDir: string;\n vision?: boolean;\n}\n\nexport async function verify(\n bundle: BundleData,\n manifest: ComposeManifest,\n videoPath: string,\n opts: VerifyOptions,\n): Promise<Verdict> {\n const verifyDir = join(opts.outDir, 'verify');\n await mkdir(verifyDir, { recursive: true });\n const ctx: VerifyContext = { bundle, manifest, videoPath, outDir: verifyDir };\n\n log.info('verifying output');\n const checks: CheckResult[] = [];\n const suite = [\n checkEncode, // fail fast on a broken file before decoding frames from it\n checkTargetInFrame,\n checkCursorOnTarget,\n checkActionEffect,\n checkOutputPixels, // the delivered MP4, not the plan\n checkFrozenBlank,\n checkCaptions,\n checkPacing,\n checkMasks,\n checkAudio,\n ];\n for (const check of suite) {\n const result = await check(ctx);\n checks.push(result);\n report(result);\n }\n\n const contactSheet = join(verifyDir, 'contact-sheet.png');\n await renderContactSheet(manifest, videoPath, contactSheet);\n log.ok(`contact sheet → ${contactSheet}`);\n\n let vision: Verdict['vision'] = null;\n if (opts.vision) {\n const { check, review } = await visionReview(contactSheet, manifest);\n checks.push(check);\n report(check);\n vision = review;\n }\n\n const failed = checks.some((c) => c.status === 'fail');\n const unsigned: Omit<Verdict, 'signature'> = {\n schema: 'playhead/verdict@2',\n verdict: failed ? 'not-publishable' : 'publishable',\n video: { path: videoPath, sha256: manifest.videoSha256 ?? (await sha256File(videoPath)) },\n bundleHashes: manifest.bundleHashes,\n provenance: {\n playheadVersion: PLAYHEAD_VERSION,\n specHash: bundle.manifest.specHash,\n appUrl: bundle.manifest.appUrl,\n capturedAt: bundle.manifest.createdAtIso,\n verifiedAt: new Date().toISOString(),\n checkSuiteVersion: CHECK_SUITE_VERSION,\n host: `${platform()}-${arch()}`,\n ...(bundle.manifest.partial ? { partial: true } : {}),\n ...(bundle.manifest.failure ? { failure: bundle.manifest.failure } : {}),\n },\n checks,\n contactSheet,\n vision,\n };\n const verdict: Verdict = { ...unsigned, signature: signVerdict(unsigned) };\n if (!verdict.signature) log.debug('verdict unsigned — set PLAYHEAD_SIGNING_KEY to sign');\n await writeFile(join(verifyDir, 'verdict.json'), JSON.stringify(verdict, null, 2));\n\n if (failed) log.error(`verdict: NOT PUBLISHABLE`);\n else log.ok(`verdict: publishable`);\n return verdict;\n}\n\n/** Re-load a compose manifest from disk (for `playhead verify <bundle> <mp4>`). */\nexport async function loadComposeManifest(path: string): Promise<ComposeManifest> {\n const manifest = JSON.parse(await readFile(path, 'utf8')) as ComposeManifest;\n if (manifest.schema !== 'playhead/compose@1') {\n throw new Error(`Unsupported compose manifest schema in ${path}`);\n }\n return manifest;\n}\n\nfunction report(c: CheckResult): void {\n const label =\n c.status === 'pass'\n ? pc.green('pass')\n : c.status === 'fail'\n ? pc.red('FAIL')\n : c.status === 'warn'\n ? pc.yellow('warn')\n : pc.dim('skip');\n console.error(` ${label} ${c.id}: ${c.details}`);\n for (const e of c.evidence ?? []) {\n console.error(pc.dim(` ${e.stepRef ?? ''}${e.t !== undefined ? ` @${(e.t / 1000).toFixed(1)}s` : ''} — ${e.note}`));\n }\n}\n","import sharp from 'sharp';\nimport { ffmpegPath, ffprobePath, runBinaryRaw, runBinary } from '../shared/ffmpeg.js';\nimport type { BundleData } from '../bundle/types.js';\nimport { frameIndexForTime, framePath } from '../bundle/reader.js';\n\n/** Extract grayscale frames from the output video at a fixed rate. */\nexport async function extractGrayFrames(\n videoPath: string,\n fps: number,\n w: number,\n h: number,\n): Promise<{ frames: Buffer[]; intervalMs: number }> {\n const res = await runBinaryRaw(ffmpegPath(), [\n '-hide_banner', '-loglevel', 'error',\n '-i', videoPath,\n '-vf', `fps=${fps},scale=${w}:${h}`,\n '-f', 'rawvideo',\n '-pix_fmt', 'gray',\n 'pipe:1',\n ]);\n if (res.code !== 0) throw new Error(`frame extraction failed: ${res.stderr}`);\n const frameSize = w * h;\n const frames: Buffer[] = [];\n for (let off = 0; off + frameSize <= res.stdout.length; off += frameSize) {\n frames.push(res.stdout.subarray(off, off + frameSize));\n }\n return { frames, intervalMs: 1000 / fps };\n}\n\n/** Extract one PNG frame from the output video at a timestamp (ms). */\nexport async function extractFrameAt(videoPath: string, tMs: number): Promise<Buffer> {\n const res = await runBinaryRaw(ffmpegPath(), [\n '-hide_banner', '-loglevel', 'error',\n '-ss', (Math.max(0, tMs) / 1000).toFixed(3),\n '-i', videoPath,\n '-frames:v', '1',\n '-f', 'image2pipe',\n '-vcodec', 'png',\n 'pipe:1',\n ]);\n if (res.code !== 0 || res.stdout.length === 0) {\n throw new Error(`could not extract frame at ${tMs}ms: ${res.stderr}`);\n }\n return res.stdout;\n}\n\nexport interface ProbeInfo {\n codec: string;\n width: number;\n height: number;\n durationSec: number;\n fps: number;\n}\n\nexport async function probeVideo(videoPath: string): Promise<ProbeInfo> {\n const res = await runBinary(ffprobePath(), [\n '-v', 'error',\n '-print_format', 'json',\n '-show_format',\n '-show_streams',\n videoPath,\n ]);\n if (res.code !== 0) throw new Error(`ffprobe failed: ${res.stderr}`);\n const json = JSON.parse(res.stdout) as {\n streams?: { codec_type: string; codec_name: string; width: number; height: number; avg_frame_rate: string }[];\n format?: { duration?: string };\n };\n const v = json.streams?.find((s) => s.codec_type === 'video');\n if (!v) throw new Error('no video stream found');\n const [num, den] = v.avg_frame_rate.split('/').map(Number);\n return {\n codec: v.codec_name,\n width: v.width,\n height: v.height,\n durationSec: Number(json.format?.duration ?? 0),\n fps: den ? num! / den : 0,\n };\n}\n\nexport function meanAbsDiff(a: Buffer, b: Buffer): number {\n const n = Math.min(a.length, b.length);\n let sum = 0;\n for (let i = 0; i < n; i++) sum += Math.abs(a[i]! - b[i]!);\n return sum / n;\n}\n\nexport function variance(a: Buffer): number {\n let sum = 0;\n for (let i = 0; i < a.length; i++) sum += a[i]!;\n const mean = sum / a.length;\n let v = 0;\n for (let i = 0; i < a.length; i++) v += (a[i]! - mean) ** 2;\n return v / a.length;\n}\n\n/** Decode a capture-bundle source frame to grayscale at reduced width. */\nexport async function sourceFrameGray(\n bundle: BundleData,\n tMs: number,\n width: number,\n): Promise<{ data: Buffer; w: number; h: number; frameT: number }> {\n const idx = frameIndexForTime(bundle.frames, tMs);\n const { data, info } = await sharp(framePath(bundle, idx))\n .resize({ width })\n .grayscale()\n .raw()\n .toBuffer({ resolveWithObject: true });\n return { data, w: info.width, h: info.height, frameT: bundle.frames[idx]!.t };\n}\n\n/** Decode a region of a source frame (frame px) to grayscale raw. */\nexport async function sourceRegionGray(\n bundle: BundleData,\n tMs: number,\n region: { x: number; y: number; w: number; h: number },\n preferAfter = false,\n color = false,\n): Promise<Buffer | null> {\n let idx = frameIndexForTime(bundle.frames, tMs);\n if (preferAfter && idx + 1 < bundle.frames.length && bundle.frames[idx]!.t < tMs) idx += 1;\n const meta = await sharp(framePath(bundle, idx)).metadata();\n const fw = meta.width ?? 0;\n const fh = meta.height ?? 0;\n const x = Math.max(0, Math.round(region.x));\n const y = Math.max(0, Math.round(region.y));\n const w = Math.min(Math.round(region.w), fw - x);\n const h = Math.min(Math.round(region.h), fh - y);\n if (w < 4 || h < 4) return null;\n // Grayscale by default (cheap); color on request — a pastel hue swap (blue→red badge) is\n // nearly luminance-neutral and INVISIBLE to a grayscale diff.\n let img = sharp(framePath(bundle, idx)).extract({ left: x, top: y, width: w, height: h });\n if (!color) img = img.grayscale();\n const { data } = await img.raw().toBuffer({ resolveWithObject: true });\n return data;\n}\n\n/** Crop a region from PNG bytes (or an image file), grayscale, resize to 48x48 raw. */\nexport async function regionGray48(input: Buffer | string, rect: { x: number; y: number; w: number; h: number }): Promise<Buffer | null> {\n try {\n const img = sharp(input);\n const meta = await img.metadata();\n const W = meta.width ?? 0;\n const H = meta.height ?? 0;\n const left = Math.max(0, Math.round(rect.x));\n const top = Math.max(0, Math.round(rect.y));\n const width = Math.min(W - left, Math.round(rect.w));\n const height = Math.min(H - top, Math.round(rect.h));\n if (width < 8 || height < 8) return null;\n return await sharp(input).extract({ left, top, width, height }).grayscale().resize(48, 48, { fit: 'fill' }).raw().toBuffer();\n } catch {\n return null;\n }\n}\n\n/** Normalized cross-correlation of two equal-length gray buffers, in [-1, 1]. */\nexport function normalizedCorrelation(a: Buffer, b: Buffer): number {\n const n = Math.min(a.length, b.length);\n let ma = 0;\n let mb = 0;\n for (let i = 0; i < n; i++) {\n ma += a[i]!;\n mb += b[i]!;\n }\n ma /= n;\n mb /= n;\n let num = 0;\n let da = 0;\n let db = 0;\n for (let i = 0; i < n; i++) {\n const xa = a[i]! - ma;\n const xb = b[i]! - mb;\n num += xa * xb;\n da += xa * xa;\n db += xb * xb;\n }\n // Two flat regions (zero variance) are \"the same\" for our purposes.\n if (da < 1e-6 || db < 1e-6) return da < 1e-6 && db < 1e-6 ? 1 : 0;\n return num / Math.sqrt(da * db);\n}\n","import type { VerifyContext, CheckResult, CheckEvidence } from './types.js';\nimport { stageContent, actReactWindows } from '../compose/types.js';\nimport { sampleCamera } from '../compose/camera/interpolate.js';\nimport { sampleCursor, type CursorPlan } from '../compose/cursor/path.js';\nimport { segmentAt, sampleSource } from '../compose/timeline/pacing.js';\nimport { actionEvents } from '../capture/events.js';\nimport { projectRect, rectContains, type CameraPlane, type Rect } from '../shared/geometry.js';\nimport {\n extractFrameAt,\n extractGrayFrames,\n meanAbsDiff,\n normalizedCorrelation,\n probeVideo,\n regionGray48,\n sourceFrameGray,\n sourceRegionGray,\n variance,\n} from './media.js';\nimport { framePath, frameIndexForTime } from '../bundle/reader.js';\nimport { ffmpegPath, ffprobePath, runBinary } from '../shared/ffmpeg.js';\n\nconst EFFECT_KINDS = new Set(['click', 'dblclick', 'type', 'select', 'goto']);\nconst CLICK_KINDS = new Set(['click', 'dblclick', 'select']);\n\n/** The camera projects into STAGE-CONTENT space (same space the planner and renderer use). */\nfunction plane(ctx: VerifyContext): CameraPlane {\n const content = stageContent(ctx.manifest.profile);\n return {\n vpW: ctx.manifest.viewport.w,\n vpH: ctx.manifest.viewport.h,\n outW: content.w,\n outH: content.h,\n };\n}\n\n/** 1. Every target legibly in frame around its action beat. */\nexport async function checkTargetInFrame(ctx: VerifyContext): Promise<CheckResult> {\n const p = plane(ctx);\n const frame: Rect = { x: 0, y: 0, w: p.outW, h: p.outH };\n const evidence: CheckEvidence[] = [];\n let checked = 0;\n let minHeight = Infinity;\n\n // Captions that are visible during a step's hold — the target must not hide behind them.\n const captions = ctx.manifest.overlays.filter((o) => o.kind === 'caption');\n for (const step of ctx.manifest.steps) {\n // The framing promise mirrors the planner exactly (same shared helper): an act→react step\n // promises the action target around the beat and the focused payoff during the settled\n // hold; otherwise the focused rect (or target) across the whole hold. The camera's travel\n // between act and react windows is unchecked by design.\n const handoff = actReactWindows(step);\n const rect = step.focusRectVp ?? step.targetRectVp;\n const windows = handoff\n ? [handoff.act, handoff.react]\n : rect\n ? [{ rect, from: Math.max(step.outStart, step.outBeat - 60), to: step.outEnd }]\n : [];\n if (windows.length === 0) continue;\n checked += 1;\n for (const w of windows)\n for (let t = w.from; t <= w.to; t += 100) {\n const rect = w.rect;\n const cam = sampleCamera(ctx.manifest.camera, t);\n const proj = projectRect(rect, cam, p);\n minHeight = Math.min(minHeight, proj.h);\n if (!rectContains(frame, proj, 2)) {\n evidence.push({ stepRef: step.stepRef, t, note: `target cropped by frame edge (projected ${fmtRect(proj)})` });\n break;\n }\n // A scroll's anchor element is just where we scrolled to — the viewer watches the list\n // move, not that element, so it need only be in frame, not meet the legibility floor.\n // Same for an explicit `focus: wide`: the author chose context over close-up, so the\n // target must be visible but is exempt from the close-up legibility floor.\n if (step.kind !== 'scroll' && step.focus !== 'wide' && proj.h < 28) {\n evidence.push({ stepRef: step.stepRef, t, note: `target renders too small (${proj.h.toFixed(0)}px high)` });\n break;\n }\n // Captions live in FRAME space; the projection is in stage-content space — translate\n // before comparing (the stage origin is (0,0) when no stage is set).\n const content = stageContent(ctx.manifest.profile);\n const projFrame: Rect = { x: proj.x + content.x, y: proj.y + content.y, w: proj.w, h: proj.h };\n const cap = captions.find((c) => t >= c.tStart + 150 && t <= c.tEnd - 150 && rectsOverlap(c.box, projFrame));\n if (cap) {\n evidence.push({ stepRef: step.stepRef, t, note: `caption \"${cap.text}\" overlaps the target` });\n break;\n }\n }\n }\n if (checked === 0) return { id: 'target-in-frame', status: 'skip', details: 'no steps with targets' };\n return evidence.length > 0\n ? { id: 'target-in-frame', status: 'fail', details: `${evidence.length}/${checked} targets violate framing`, evidence }\n : {\n id: 'target-in-frame',\n status: 'pass',\n details: `${checked}/${checked} targets fully framed, min rendered height ${minHeight === Infinity ? '—' : minHeight.toFixed(0) + 'px'}`,\n };\n}\n\n/** 2. Rendered cursor sits on the target at each click beat. */\nexport async function checkCursorOnTarget(ctx: VerifyContext): Promise<CheckResult> {\n const cursorPlan: CursorPlan = {\n segments: ctx.manifest.cursor,\n ripples: ctx.manifest.ripples,\n restStart: { x: ctx.manifest.viewport.w / 2, y: ctx.manifest.viewport.h * 0.6 },\n };\n const evidence: CheckEvidence[] = [];\n let checked = 0;\n for (const step of ctx.manifest.steps) {\n if (!CLICK_KINDS.has(step.kind) || !step.targetRectVp) continue;\n checked += 1;\n const pos = sampleCursor(cursorPlan, step.outBeat);\n const r = step.targetRectVp;\n const pad = 4;\n const inside =\n pos.x >= r.x - pad && pos.x <= r.x + r.w + pad && pos.y >= r.y - pad && pos.y <= r.y + r.h + pad;\n if (!inside) {\n evidence.push({\n stepRef: step.stepRef,\n t: step.outBeat,\n note: `cursor at (${pos.x.toFixed(0)},${pos.y.toFixed(0)}) missed target ${fmtRect(r)}`,\n });\n }\n }\n if (checked === 0) return { id: 'cursor-on-target', status: 'skip', details: 'no click steps' };\n return evidence.length > 0\n ? { id: 'cursor-on-target', status: 'fail', details: `${evidence.length}/${checked} clicks miss their target`, evidence }\n : { id: 'cursor-on-target', status: 'pass', details: `${checked}/${checked} clicks land on target` };\n}\n\n/** 3. Every action visibly changed the UI (dead-click detection). */\nexport async function checkActionEffect(ctx: VerifyContext): Promise<CheckResult> {\n const evidence: CheckEvidence[] = [];\n const inconclusive: CheckEvidence[] = [];\n let checked = 0;\n const frameScale = ctx.bundle.manifest.frameW / ctx.manifest.viewport.w;\n\n const lastFrameT = ctx.bundle.frames[ctx.bundle.frames.length - 1]!.t;\n const steps = ctx.manifest.steps;\n let skippedMasked = 0;\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]!;\n if (!EFFECT_KINDS.has(step.kind)) continue;\n // A masked field intentionally hides its own change — its effect is unverifiable by design.\n if (step.masked) {\n skippedMasked += 1;\n continue;\n }\n checked += 1;\n // Sample the \"after\" state at this step's settled hold, just before the next action — for an\n // instant hash-route navigation the settle timestamp itself can precede the first post-nav\n // frame, so compare against the fully-settled view instead.\n const nextAction = i + 1 < steps.length ? steps[i + 1]!.srcAction : lastFrameT;\n const afterT = Math.max(step.srcSettled, nextAction - 60);\n const before = await sourceFrameGray(ctx.bundle, step.srcAction - 40, 320);\n const after = await sourceFrameGray(ctx.bundle, afterT, 320);\n if (after.frameT <= before.frameT) {\n // No distinct post-action frame was captured (a capture-loop gap, e.g. under CPU load).\n // Absence of frames can't prove absence of effect, so this is inconclusive, not a failure.\n inconclusive.push({ stepRef: step.stepRef, note: 'no post-action frame captured to compare' });\n continue;\n }\n if (before.frameT >= step.srcAction) {\n // The \"before\" sample clamped to a frame AT/AFTER the action (no pre-action footage —\n // e.g. the first grabs stalled during initial load). Comparing post to post proves\n // nothing either way.\n inconclusive.push({ stepRef: step.stepRef, note: 'no pre-action frame captured to compare' });\n continue;\n }\n const overall = meanAbsDiff(before.data, after.data);\n let regionDiff = 0;\n // Measure where the effect is EXPECTED: the action target, and — for act→react steps —\n // the focused payoff (changing a select recolors the badge ELSEWHERE; the payoff region\n // is where the change actually lands). Take the strongest signal.\n const regions = [step.targetRectVp, step.focusRectVp].filter((r): r is Rect => !!r);\n for (const r of regions) {\n const region = scaleRect(r, frameScale);\n const [ra, rb] = await Promise.all([\n sourceRegionGray(ctx.bundle, step.srcAction - 40, region, false, true),\n sourceRegionGray(ctx.bundle, afterT, region, true, true),\n ]);\n if (ra && rb && ra.length === rb.length) regionDiff = Math.max(regionDiff, meanAbsDiff(ra, rb));\n }\n // Typing changes only a few pixels page-wide, so the local target region is the real signal.\n if (overall < 0.5 && regionDiff < 2) {\n evidence.push({\n stepRef: step.stepRef,\n t: step.outBeat,\n note: `no visible effect (frame diff ${overall.toFixed(2)}, target diff ${regionDiff.toFixed(2)})`,\n });\n }\n }\n if (checked === 0) {\n return {\n id: 'action-effect',\n status: 'skip',\n details: skippedMasked > 0 ? `no verifiable actions (${skippedMasked} masked)` : 'no effectful actions',\n };\n }\n const maskedNote = skippedMasked > 0 ? ` (${skippedMasked} masked skipped)` : '';\n const inconcNote = inconclusive.length > 0 ? `, ${inconclusive.length} inconclusive (capture gap)` : '';\n if (evidence.length > 0) {\n return {\n id: 'action-effect',\n status: 'fail',\n details: `${evidence.length}/${checked} actions show no visible effect${maskedNote}${inconcNote}`,\n evidence: [...evidence, ...inconclusive],\n };\n }\n if (inconclusive.length > 0) {\n return {\n id: 'action-effect',\n status: 'warn',\n details: `${checked - inconclusive.length}/${checked} actions visibly effective; ${inconclusive.length} unverified (capture gap)${maskedNote}`,\n evidence: inconclusive,\n };\n }\n return { id: 'action-effect', status: 'pass', details: `${checked}/${checked} actions visibly effective${maskedNote}` };\n}\n\n/** 4. No unplanned frozen footage, no blank frames, in the delivered video. */\nexport async function checkFrozenBlank(ctx: VerifyContext): Promise<CheckResult> {\n const { frames, intervalMs } = await extractGrayFrames(ctx.videoPath, 2, 320, 180);\n if (frames.length < 2) return { id: 'frozen-blank', status: 'fail', details: 'could not decode output frames' };\n const evidence: CheckEvidence[] = [];\n\n // Intentional near-uniform frames: title cards, and the dip-to-background fades around them\n // (which momentarily paint mostly theme background). These are design, not dead footage.\n const dips = ctx.manifest.overlays.filter((o) => o.kind === 'dip');\n const inTransition = (t: number) =>\n segmentAt(ctx.manifest.segments, t).kind === 'card' || dips.some((d) => t >= d.tStart - 60 && t <= d.tEnd + 60);\n\n // Blank frames.\n for (let i = 0; i < frames.length; i++) {\n const t = i * intervalMs;\n if (inTransition(t)) continue;\n if (variance(frames[i]!) < 2) {\n evidence.push({ t, note: `blank frame at ${(t / 1000).toFixed(1)}s` });\n }\n }\n\n // Frozen runs: identical stretches that cross more than one step beat, or absurdly long.\n // A masked step is intentionally static on screen (the overlay hides the typing), so its\n // window is legitimately \"frozen\" — exclude it, as action-effect does.\n const maskedWindows = ctx.manifest.steps\n .filter((s) => s.masked)\n .map((s) => ({ start: s.outStart, end: s.outEnd }));\n const inMaskedWindow = (t0: number, t1: number) =>\n maskedWindows.some((w) => t1 >= w.start - 200 && t0 <= w.end + 200);\n\n // The final section (last action through the outro) is an intended hold on the result — a\n // walkthrough often ends held on its final state — so static footage there is not a stall.\n const lastBeat = ctx.manifest.steps.reduce((m, s) => Math.max(m, s.outBeat), 0);\n\n // A narrated video legitimately holds on a static screen WHILE ITS SPOKEN LINE PLAYS — the\n // voice carries it. But that must never blanket-disable stall detection: a frozen run is only\n // exempt when a narration clip actually covers it. (Manifests from before clip windows were\n // recorded fall back to the blanket exemption rather than mis-failing old renders.)\n const narrated = !!ctx.manifest.audio?.narrated;\n const clipWindows = (ctx.manifest.audio?.clips ?? []).map((c) => ({\n start: c.tStart - 300,\n end: c.tStart + c.durMs + 1200, // clip + the tail-and-extend hold pacing grants it\n }));\n const voiceCovers = (t0: number, t1: number) =>\n clipWindows.length === 0\n ? narrated // legacy manifests: no window data — keep the old blanket behavior\n : clipWindows.some((w) => t0 >= w.start && t1 <= w.end);\n\n let runStart = 0;\n for (let i = 1; i <= frames.length; i++) {\n const identical = i < frames.length && meanAbsDiff(frames[i]!, frames[i - 1]!) < 0.15;\n if (!identical) {\n const runMs = (i - 1 - runStart) * intervalMs;\n const t0 = runStart * intervalMs;\n const t1 = (i - 1) * intervalMs;\n const inFinalHold = t0 >= lastBeat - 800;\n if (runMs > 2000 && !inMaskedWindow(t0, t1) && !inFinalHold && !(narrated && voiceCovers(t0, t1))) {\n const beatsInside = ctx.manifest.steps.filter((s) => s.outBeat > t0 + 200 && s.outBeat < t1 - 200);\n if (beatsInside.length >= 1 && runMs > 2500) {\n evidence.push({\n t: t0,\n note: `frozen footage ${(runMs / 1000).toFixed(1)}s spanning ${beatsInside.length} action beat(s)`,\n });\n } else if (runMs > 8000) {\n evidence.push({ t: t0, note: `frozen footage for ${(runMs / 1000).toFixed(1)}s` });\n }\n }\n runStart = i;\n }\n }\n return evidence.length > 0\n ? { id: 'frozen-blank', status: 'fail', details: `${evidence.length} frozen/blank issue(s)`, evidence }\n : { id: 'frozen-blank', status: 'pass', details: `${frames.length} sampled output frames live and non-blank` };\n}\n\n/** 5. Captions legible: no truncation, font floor respected, inside safe bounds. */\nexport async function checkCaptions(ctx: VerifyContext): Promise<CheckResult> {\n const evidence: CheckEvidence[] = [];\n let warned = 0;\n let count = 0;\n const out: Rect = { x: 0, y: 0, w: ctx.manifest.profile.width, h: ctx.manifest.profile.height };\n for (const o of ctx.manifest.overlays) {\n if (o.kind !== 'caption') continue;\n count += 1;\n if (o.truncated) evidence.push({ stepRef: o.stepRef, note: `caption truncated: \"${o.text}\"` });\n if (o.fontPx < ctx.manifest.theme.captionMinFontPx)\n evidence.push({ stepRef: o.stepRef, note: `caption font ${o.fontPx}px below minimum` });\n if (!rectContains(out, o.box, 24)) evidence.push({ stepRef: o.stepRef, note: 'caption box outside safe bounds' });\n if (o.shrunk && !o.truncated) warned += 1;\n }\n if (count === 0) return { id: 'captions', status: 'skip', details: 'no captions' };\n if (evidence.length > 0)\n return { id: 'captions', status: 'fail', details: `${evidence.length} caption problem(s)`, evidence };\n return warned > 0\n ? { id: 'captions', status: 'warn', details: `${count} captions ok, ${warned} auto-shrunk to fit` }\n : { id: 'captions', status: 'pass', details: `${count} captions fit at full size` };\n}\n\n/** 6. Pacing sanity: steps get readable screen time; total duration sane. */\nexport async function checkPacing(ctx: VerifyContext): Promise<CheckResult> {\n const evidence: CheckEvidence[] = [];\n for (const step of ctx.manifest.steps) {\n const dur = step.outEnd - step.outStart;\n if (step.kind !== 'wait' && dur < 1200) {\n evidence.push({ stepRef: step.stepRef, note: `step on screen only ${(dur / 1000).toFixed(1)}s` });\n }\n }\n const total = ctx.manifest.durationMs;\n if (total < 3000) evidence.push({ note: `video too short (${(total / 1000).toFixed(1)}s)` });\n if (total > 15 * 60_000) evidence.push({ note: `video too long (${(total / 60000).toFixed(1)}min)` });\n return evidence.length > 0\n ? { id: 'pacing', status: 'fail', details: `${evidence.length} pacing violation(s)`, evidence }\n : { id: 'pacing', status: 'pass', details: `${ctx.manifest.steps.length} steps paced ≥1.2s, total ${(total / 1000).toFixed(1)}s` };\n}\n\n/** 7. The MP4 itself is intact and matches the manifest. */\n/** 9. Narration audio: when the video was narrated, the track must exist, be audible, and span the video. */\nexport async function checkAudio(ctx: VerifyContext): Promise<CheckResult> {\n if (!ctx.manifest.audio?.narrated) return { id: 'audio', status: 'skip', details: 'no narration' };\n const evidence: CheckEvidence[] = [];\n\n const probe = await runBinary(ffprobePath(), [\n '-v', 'error', '-select_streams', 'a', '-show_entries', 'stream=codec_name,duration', '-of', 'json', ctx.videoPath,\n ]);\n const stream = (JSON.parse(probe.stdout) as { streams?: { codec_name: string; duration?: string }[] }).streams?.[0];\n if (!stream) return { id: 'audio', status: 'fail', details: 'narration requested but the output has no audio stream' };\n\n // Non-silent? volumedetect reports mean/peak levels on stderr.\n const vd = await runBinary(ffmpegPath(), ['-hide_banner', '-nostats', '-i', ctx.videoPath, '-af', 'volumedetect', '-f', 'null', '-']);\n const mean = Number(/mean_volume:\\s*(-?[\\d.]+) dB/.exec(vd.stderr)?.[1] ?? '0');\n if (mean <= -70) evidence.push({ note: `narration track is effectively silent (mean ${mean} dB)` });\n\n const expectSec = ctx.manifest.durationMs / 1000;\n const aDur = Number(stream.duration ?? 0);\n if (aDur > 0 && Math.abs(aDur - expectSec) > Math.max(0.5, expectSec * 0.05))\n evidence.push({ note: `audio ${aDur.toFixed(1)}s vs video ${expectSec.toFixed(1)}s` });\n\n // A/V SYNC: every narration clip must be AUDIBLE inside its own window. Pacing predicts and\n // mux places independently — a drift bug would otherwise ship a voice describing the\n // previous screen with a passing verdict.\n const clips = ctx.manifest.audio.clips ?? [];\n let loudness: number | null = null;\n if (clips.length > 0) {\n const det = await runBinary(ffmpegPath(), [\n '-hide_banner', '-nostats',\n '-i', ctx.videoPath,\n '-af', 'silencedetect=noise=-40dB:d=0.35,ebur128',\n '-f', 'null', '-',\n ]);\n const silences: { start: number; end: number }[] = [];\n let open: number | null = null;\n for (const m of det.stderr.matchAll(/silence_(start|end): ([\\d.]+)/g)) {\n if (m[1] === 'start') open = parseFloat(m[2]!) * 1000;\n else if (open !== null) {\n silences.push({ start: open, end: parseFloat(m[2]!) * 1000 });\n open = null;\n }\n }\n if (open !== null) silences.push({ start: open, end: ctx.manifest.durationMs });\n for (const clip of clips) {\n const w0 = clip.tStart;\n const w1 = clip.tStart + clip.durMs;\n let silent = 0;\n for (const s of silences) {\n silent += Math.max(0, Math.min(w1, s.end) - Math.max(w0, s.start));\n }\n const voiced = (w1 - w0 - silent) / Math.max(1, w1 - w0);\n if (voiced < 0.45) {\n evidence.push({\n stepRef: clip.stepRef,\n t: clip.tStart,\n note: `narration line is mostly silent in its own window (${(voiced * 100).toFixed(0)}% voiced) — audio/video drift`,\n });\n }\n }\n // Loudness: the mix normalizes to I=-16 LUFS; a big miss means the loudnorm stage broke.\n // ebur128 prints PERIODIC \"I:\" readouts (starting at -70 before audio plays) and a final\n // summary — the integrated value is the LAST match, never the first.\n const lus = [...det.stderr.matchAll(/I:\\s+(-?[\\d.]+)\\s+LUFS/g)];\n const lu = lus[lus.length - 1];\n if (lu) {\n loudness = parseFloat(lu[1]!);\n if (loudness < -20 || loudness > -12) {\n evidence.push({ note: `integrated loudness ${loudness.toFixed(1)} LUFS is outside the -16±4 target` });\n }\n }\n }\n\n return evidence.length\n ? { id: 'audio', status: 'fail', details: `${evidence.length} narration problem(s)`, evidence }\n : {\n id: 'audio',\n status: 'pass',\n details: `${ctx.manifest.audio.lines} lines audible in their windows, ${stream.codec_name}${loudness !== null ? `, ${loudness.toFixed(1)} LUFS` : `, mean ${mean.toFixed(0)} dB`}`,\n };\n}\n\nexport async function checkEncode(ctx: VerifyContext): Promise<CheckResult> {\n let info;\n try {\n info = await probeVideo(ctx.videoPath);\n } catch (e) {\n return { id: 'encode', status: 'fail', details: `unreadable video: ${(e as Error).message}` };\n }\n const problems: string[] = [];\n if (info.codec !== 'h264') problems.push(`codec ${info.codec}`);\n if (info.width !== ctx.manifest.profile.width || info.height !== ctx.manifest.profile.height)\n problems.push(`resolution ${info.width}x${info.height}`);\n const expectSec = ctx.manifest.durationMs / 1000;\n if (Math.abs(info.durationSec - expectSec) > Math.max(0.5, expectSec * 0.03))\n problems.push(`duration ${info.durationSec.toFixed(1)}s vs planned ${expectSec.toFixed(1)}s`);\n if (Math.abs(info.fps - ctx.manifest.profile.fps) > 0.5) problems.push(`fps ${info.fps.toFixed(2)}`);\n return problems.length > 0\n ? { id: 'encode', status: 'fail', details: problems.join('; ') }\n : {\n id: 'encode',\n status: 'pass',\n details: `h264 ${info.width}x${info.height} @ ${info.fps.toFixed(0)}fps, ${info.durationSec.toFixed(1)}s`,\n };\n}\n\n/** 8. Masking held: masked regions are covered in footage, secrets absent from the log. */\nexport async function checkMasks(ctx: VerifyContext): Promise<CheckResult> {\n const evidence: CheckEvidence[] = [];\n const frameScale = ctx.bundle.manifest.frameW / ctx.manifest.viewport.w;\n\n // A mask region can be legitimately occluded by later UI (a dialog opening over a banner),\n // which raises its variance without exposing the sensitive pixels. So group samples by\n // position and require that each masked element reads as covered in its BEST sample —\n // if masking failed entirely, no sample of that element would ever be uniform.\n const buckets = new Map<string, { rect: { x: number; y: number; w: number; h: number }; minSd: number; t: number }>();\n const blurKeys = new Set<string>();\n for (const sample of ctx.bundle.maskSamples) {\n for (const rect of sample.rects) {\n const posKey = `${Math.round(rect.x / 24)}:${Math.round(rect.y / 24)}:${Math.round(rect.w / 24)}:${Math.round(rect.h / 24)}`;\n if (rect.style === 'blur') {\n blurKeys.add(posKey);\n continue; // a blurred region has no reference to compare against; leave it to --vision\n }\n const inset = scaleRect(shrinkRect(rect, Math.min(6, rect.w / 8, rect.h / 8)), frameScale);\n const region = await sourceRegionGray(ctx.bundle, sample.t + 60, inset, true);\n if (!region) continue;\n const sd = Math.sqrt(variance(region));\n const key = posKey;\n const prev = buckets.get(key);\n if (!prev || sd < prev.minSd) buckets.set(key, { rect, minSd: sd, t: sample.t });\n }\n }\n for (const b of buckets.values()) {\n if (b.minSd > 16) {\n evidence.push({ t: b.t, note: `solid mask at ${fmtRect(b.rect)} never verified opaque (best σ=${b.minSd.toFixed(1)})` });\n }\n }\n\n for (const e of actionEvents(ctx.bundle.events)) {\n if (e.masked && e.typedText && /[^•]/.test(e.typedText)) {\n evidence.push({ stepRef: `${e.sceneId}/${e.stepIndex}`, note: 'masked step leaked typed text into the event log' });\n }\n }\n\n if (ctx.bundle.maskSamples.length === 0) {\n return { id: 'masks', status: 'skip', details: 'no masking rules' };\n }\n if (evidence.length > 0) {\n return { id: 'masks', status: 'fail', details: `${evidence.length} mask violation(s)`, evidence };\n }\n const parts: string[] = [];\n if (buckets.size > 0) parts.push(`${buckets.size} solid region(s) verified opaque`);\n if (blurKeys.size > 0) parts.push(`${blurKeys.size} blurred region(s) applied`);\n return { id: 'masks', status: 'pass', details: `${parts.join(', ')}; log clean` };\n}\n\nfunction scaleRect(r: Rect, s: number): Rect {\n return { x: r.x * s, y: r.y * s, w: r.w * s, h: r.h * s };\n}\n\nfunction rectsOverlap(a: Rect, b: Rect): boolean {\n return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;\n}\n\nfunction shrinkRect(r: { x: number; y: number; w: number; h: number }, by: number): Rect {\n return { x: r.x + by, y: r.y + by, w: Math.max(1, r.w - 2 * by), h: Math.max(1, r.h - 2 * by) };\n}\n\nfunction fmtRect(r: Rect): string {\n return `[${r.x.toFixed(0)},${r.y.toFixed(0)} ${r.w.toFixed(0)}x${r.h.toFixed(0)}]`;\n}\n\n/**\n * 10. The DELIVERED pixels match the plan: for sampled steps, the region of the output MP4\n * where the subject should be must correlate with the same region of the source bundle frame.\n * Every geometry check above re-runs the planner's math — this one closes the plan-vs-pixels\n * hole: a renderer drawing the wrong frame or the wrong crop fails HERE.\n */\nexport async function checkOutputPixels(ctx: VerifyContext): Promise<CheckResult> {\n const p = plane(ctx);\n const content = stageContent(ctx.manifest.profile);\n const frameScale = ctx.bundle.manifest.frameW / ctx.manifest.viewport.w;\n const captions = ctx.manifest.overlays.filter((o) => o.kind === 'caption');\n\n const candidates = ctx.manifest.steps.filter((s) => !s.masked && (s.focusRectVp ?? s.targetRectVp));\n // Sample evenly, capped for speed — this decodes output frames.\n const stride = Math.max(1, Math.floor(candidates.length / 6));\n const sampled = candidates.filter((_, i) => i % stride === 0).slice(0, 6);\n if (sampled.length === 0) return { id: 'output-pixels', status: 'skip', details: 'no steps with targets' };\n\n const evidence: CheckEvidence[] = [];\n let checked = 0;\n for (const step of sampled) {\n const rect = step.focusRectVp ?? step.targetRectVp!;\n const tOut = Math.max(step.outBeat + 100, step.outEnd - 250);\n const cam = sampleCamera(ctx.manifest.camera, tOut);\n const proj = projectRect(rect, cam, p);\n const projFrame: Rect = { x: proj.x + content.x, y: proj.y + content.y, w: proj.w, h: proj.h };\n // A caption overlapping the region would pollute the comparison — skip those samples.\n if (captions.some((c) => tOut >= c.tStart && tOut <= c.tEnd && rectsOverlap(c.box, projFrame))) continue;\n const { srcAt } = sampleSource(ctx.manifest.segments, tOut);\n if (srcAt === null) continue;\n\n const outPng = await extractFrameAt(ctx.videoPath, tOut).catch(() => null);\n if (!outPng) continue;\n const outRegion = await regionGray48(outPng, projFrame);\n const srcFile = framePath(ctx.bundle, frameIndexForTime(ctx.bundle.frames, srcAt));\n const srcRegion = await regionGray48(srcFile, {\n x: rect.x * frameScale,\n y: rect.y * frameScale,\n w: rect.w * frameScale,\n h: rect.h * frameScale,\n });\n if (!outRegion || !srcRegion) continue;\n // A flat (zero-variance) region proves nothing: it can be a legitimately blank area, a mask\n // overlay, or a transition frame — and correlation against flatness is undefined. Only a\n // TEXTURED-vs-TEXTURED mismatch demonstrates a wrong frame or wrong crop.\n if (variance(outRegion) < 4 || variance(srcRegion) < 4) continue;\n checked += 1;\n const corr = normalizedCorrelation(outRegion, srcRegion);\n // Loose threshold: JPEG, rescaling, frame blending, and the spotlight all perturb pixels;\n // a WRONG frame or crop scores near zero, a right-but-processed one scores high.\n if (corr < 0.5) {\n evidence.push({\n stepRef: step.stepRef,\n t: tOut,\n note: `output region does not match the planned source region (correlation ${corr.toFixed(2)})`,\n });\n }\n }\n if (checked === 0) return { id: 'output-pixels', status: 'skip', details: 'no comparable samples (captions overlapped or frames unavailable)' };\n return evidence.length > 0\n ? { id: 'output-pixels', status: 'fail', details: `${evidence.length}/${checked} sampled regions diverge from the plan`, evidence }\n : { id: 'output-pixels', status: 'pass', details: `${checked} sampled output regions match their planned source` };\n}\n","import { writeFile } from 'node:fs/promises';\nimport { createCanvas, loadImage } from '@napi-rs/canvas';\nimport type { ComposeManifest } from '../compose/types.js';\nimport { extractFrameAt } from './media.js';\nimport { registerFonts } from '../theme/index.js';\nimport { roundRect } from '../compose/overlays/text.js';\n\nconst TILE_W = 480;\nconst LABEL_H = 42;\nconst GUTTER = 16;\nconst COLS = 3;\n\n/**\n * Contact sheet: one tile per step at its action beat (decoded from the OUTPUT video —\n * what viewers actually see) plus first and last frames, annotated with captions.\n */\nexport async function renderContactSheet(\n manifest: ComposeManifest,\n videoPath: string,\n outPath: string,\n): Promise<string> {\n registerFonts();\n const tileH = Math.round((TILE_W * manifest.profile.height) / manifest.profile.width);\n const captionsByStep = new Map(\n manifest.overlays.filter((o) => o.kind === 'caption').map((o) => [o.stepRef, o]),\n );\n\n const moments: { t: number; label: string }[] = [\n { t: manifest.overlays.find((o) => o.kind === 'titleCard')!.tEnd / 2, label: 'Title' },\n ];\n for (const step of manifest.steps) {\n const caption = captionsByStep.get(step.stepRef);\n // Sample the SETTLED hold, not the beat: at the beat (+150ms) a slow effect — a navigation,\n // a fetch, a modal — hasn't painted yet, so the tile labelled \"Click Save\" would show the\n // screen from *before* Save was clicked. Sampling near the end of the step's hold shows the\n // effect the caption claims. (Clamped to stay after the beat for very short steps.)\n const label = caption ? `${caption.ordinal}. ${caption.text}` : `${step.kind} (${step.stepRef})`;\n const settled = Math.max(step.outBeat + 150, step.outEnd - 400);\n moments.push({ t: Math.min(settled, step.outEnd - 50), label });\n }\n moments.push({ t: manifest.durationMs - 200, label: 'Final state' });\n\n const rows = Math.ceil(moments.length / COLS);\n const width = GUTTER + COLS * (TILE_W + GUTTER);\n const height = GUTTER + rows * (tileH + LABEL_H + GUTTER);\n const canvas = createCanvas(width, height);\n const ctx = canvas.getContext('2d');\n ctx.fillStyle = '#14161d';\n ctx.fillRect(0, 0, width, height);\n\n for (let i = 0; i < moments.length; i++) {\n const m = moments[i]!;\n const col = i % COLS;\n const row = Math.floor(i / COLS);\n const x = GUTTER + col * (TILE_W + GUTTER);\n const y = GUTTER + row * (tileH + LABEL_H + GUTTER);\n try {\n const png = await extractFrameAt(videoPath, m.t);\n const img = await loadImage(png);\n ctx.drawImage(img, x, y, TILE_W, tileH);\n } catch {\n ctx.fillStyle = '#3a2030';\n ctx.fillRect(x, y, TILE_W, tileH);\n ctx.fillStyle = '#ffffff';\n ctx.font = '16px Inter Medium';\n ctx.textAlign = 'center';\n ctx.fillText('frame unavailable', x + TILE_W / 2, y + tileH / 2);\n }\n // Label bar\n ctx.fillStyle = '#1e222c';\n roundRect(ctx, x, y + tileH + 4, TILE_W, LABEL_H - 8, 6);\n ctx.fill();\n ctx.fillStyle = 'rgba(255,255,255,0.92)';\n ctx.font = '15px Inter Medium';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(truncate(m.label, 58), x + 12, y + tileH + 4 + (LABEL_H - 8) / 2 + 1);\n ctx.fillStyle = 'rgba(255,255,255,0.45)';\n ctx.font = '13px Inter';\n ctx.textAlign = 'right';\n ctx.fillText(`${(m.t / 1000).toFixed(1)}s`, x + TILE_W - 12, y + tileH + 4 + (LABEL_H - 8) / 2 + 1);\n }\n\n await writeFile(outPath, await canvas.encode('png'));\n return outPath;\n}\n\nfunction truncate(s: string, n: number): string {\n return s.length <= n ? s : s.slice(0, n - 1) + '…';\n}\n","import { readFile } from 'node:fs/promises';\nimport type { CheckResult } from './types.js';\nimport type { ComposeManifest } from '../compose/types.js';\nimport { log } from '../shared/log.js';\n\nconst DEFAULT_MODEL = process.env.PLAYHEAD_VISION_MODEL ?? 'claude-opus-5';\n\nexport interface VisionReview {\n model: string;\n findings: { severity: string; note: string }[];\n}\n\n/**\n * Optional AI review: sends the contact sheet to Claude for a judgment call the\n * deterministic checks can't make (\"does this read as a coherent, professional\n * walkthrough?\"). Advisory only — findings become warn-level check entries.\n */\nexport async function visionReview(\n contactSheetPath: string,\n manifest: ComposeManifest,\n): Promise<{ check: CheckResult; review: VisionReview | null }> {\n if (!process.env.ANTHROPIC_API_KEY) {\n return {\n check: { id: 'vision-review', status: 'skip', details: 'ANTHROPIC_API_KEY not set' },\n review: null,\n };\n }\n try {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const client = new Anthropic();\n const png = await readFile(contactSheetPath);\n const captions = manifest.overlays\n .filter((o) => o.kind === 'caption')\n .map((o) => `${o.ordinal}. ${o.text}`)\n .join('\\n');\n\n const response = await client.messages.create({\n model: DEFAULT_MODEL,\n max_tokens: 1200,\n messages: [\n {\n role: 'user',\n content: [\n {\n type: 'image',\n source: { type: 'base64', media_type: 'image/png', data: png.toString('base64') },\n },\n {\n type: 'text',\n text: [\n 'This is a contact sheet of key moments from an automatically produced product walkthrough video.',\n 'Each tile shows the output frame at one step, labeled with its instruction caption. The steps are:',\n captions,\n '',\n 'Review it as a demanding video editor. Report only real problems a viewer would notice:',\n 'illegible or clipped UI, captions that do not match what is on screen, awkward framing,',\n 'visual glitches, or anything unprofessional. Ignore the tile borders and labels themselves.',\n 'Respond with strict JSON: {\"findings\": [{\"severity\": \"warn\", \"note\": \"...\"}]} —',\n 'an empty findings array if the video looks publishable.',\n ].join('\\n'),\n },\n ],\n },\n ],\n });\n const text = response.content\n .map((b) => (b.type === 'text' ? b.text : ''))\n .join('');\n const parsed = extractJson(text);\n const findings = Array.isArray(parsed?.findings)\n ? parsed.findings\n .filter((f): f is { severity?: string; note?: string } => !!f && typeof f === 'object')\n .map((f) => ({ severity: String(f.severity ?? 'warn'), note: String(f.note ?? '') }))\n : [];\n const review: VisionReview = { model: DEFAULT_MODEL, findings };\n return {\n check: {\n id: 'vision-review',\n status: findings.length > 0 ? 'warn' : 'pass',\n details:\n findings.length > 0\n ? `${findings.length} advisory finding(s) from ${DEFAULT_MODEL}`\n : `no issues flagged by ${DEFAULT_MODEL}`,\n ...(findings.length > 0 ? { evidence: findings.map((f) => ({ note: f.note })) } : {}),\n },\n review,\n };\n } catch (e) {\n log.warn(`vision review failed: ${(e as Error).message}`);\n return {\n check: { id: 'vision-review', status: 'skip', details: `vision review errored: ${(e as Error).message}` },\n review: null,\n };\n }\n}\n\nfunction extractJson(text: string): { findings?: unknown[] } | null {\n const start = text.indexOf('{');\n const end = text.lastIndexOf('}');\n if (start === -1 || end <= start) return null;\n try {\n return JSON.parse(text.slice(start, end + 1)) as { findings?: unknown[] };\n } catch {\n return null;\n }\n}\n","import { createHmac } from 'node:crypto';\nimport type { Verdict } from './types.js';\n\n/**\n * The canonical signable payload: everything that makes the verdict a CLAIM (result, artifact\n * hashes, provenance, per-check outcomes), in a fixed key order. Paths are excluded — moving\n * files doesn't change what was proven.\n */\nexport function signablePayload(v: Omit<Verdict, 'signature'>): string {\n return JSON.stringify({\n schema: v.schema,\n verdict: v.verdict,\n videoSha256: v.video.sha256,\n bundleHashes: { events: v.bundleHashes.events, framesIndex: v.bundleHashes.framesIndex },\n provenance: {\n playheadVersion: v.provenance.playheadVersion,\n specHash: v.provenance.specHash,\n appUrl: v.provenance.appUrl,\n capturedAt: v.provenance.capturedAt,\n verifiedAt: v.provenance.verifiedAt,\n checkSuiteVersion: v.provenance.checkSuiteVersion,\n host: v.provenance.host,\n partial: v.provenance.partial ?? false,\n },\n checks: v.checks.map((c) => ({ id: c.id, status: c.status })),\n });\n}\n\n/** HMAC-SHA256 signature over the canonical payload; null when no key is configured. */\nexport function signVerdict(v: Omit<Verdict, 'signature'>, key = process.env.PLAYHEAD_SIGNING_KEY): string | null {\n if (!key) return null;\n return createHmac('sha256', key).update(signablePayload(v)).digest('hex');\n}\n\n/** JUnit XML: one testsuite per verdict, one testcase per check — the shape every CI ingests. */\nexport function toJUnit(v: Verdict, suiteName = 'playhead'): string {\n const failures = v.checks.filter((c) => c.status === 'fail').length;\n const skipped = v.checks.filter((c) => c.status === 'skip').length;\n const esc = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n const cases = v.checks\n .map((c) => {\n const body =\n c.status === 'fail'\n ? `\\n <failure message=\"${esc(c.details)}\">${esc(\n (c.evidence ?? []).map((e) => `${e.stepRef ?? ''}${e.t !== undefined ? ` @${(e.t / 1000).toFixed(1)}s` : ''} — ${e.note}`).join('\\n'),\n )}</failure>\\n `\n : c.status === 'skip'\n ? `\\n <skipped message=\"${esc(c.details)}\"/>\\n `\n : '';\n return ` <testcase classname=\"${esc(suiteName)}\" name=\"${esc(c.id)}\">${body}</testcase>`;\n })\n .join('\\n');\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuite name=\"${esc(suiteName)}\" tests=\"${v.checks.length}\" failures=\"${failures}\" skipped=\"${skipped}\">\n${cases}\n</testsuite>\n`;\n}\n"],"mappings":"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","names":["ctx","join","count","plane","join","sleep","writeFile","round1","readFile","join","join","writeFile","join","dirname","createRequire","require","log","log","log","plane","shot","log","plan","log","lowerFirst","createCanvas","ctx","ctx","sharp","createCanvas","sharp","createCanvas","ctx","spawn","createRequire","require","spawn","plane","createCanvas","ctx","mkdir","writeFile","existsSync","join","createHash","createRequire","require","ffprobePath","execFile","promisify","mkdir","existsSync","join","createRequire","require","createRequire","ffmpegPath","exec","promisify","execFile","mkdir","join","existsSync","join","writeFile","join","mkdir","writeFile","readFile","sharp","sharp","CLICK_KINDS","ctx","rect","writeFile","createCanvas","createCanvas","ctx","truncate","writeFile","readFile","readFile","pc","join","mkdir","ctx","writeFile","pc"]}
|
|
1
|
+
{"version":3,"sources":["../src/spec/parse.ts","../src/spec/schema.ts","../src/spec/locators.ts","../src/capture/executor.ts","../src/capture/playwright-driver.ts","../src/shared/easing.ts","../src/shared/log.ts","../src/shared/exit.ts","../src/bundle/writer.ts","../src/bundle/hash.ts","../src/shared/version.ts","../src/shared/geometry.ts","../src/bundle/reader.ts","../src/compose/index.ts","../src/theme/index.ts","../src/compose/types.ts","../src/compose/kinds.ts","../src/capture/events.ts","../src/audio/timing.ts","../src/compose/timeline/pacing.ts","../src/compose/camera/interpolate.ts","../src/compose/camera/planner.ts","../src/compose/cursor/path.ts","../src/compose/captions.ts","../src/compose/overlays/text.ts","../src/compose/overlays/build.ts","../src/compose/render/renderer.ts","../src/compose/cursor/render.ts","../src/compose/overlays/draw.ts","../src/compose/render/frameStore.ts","../src/compose/render/encoder.ts","../src/shared/ffmpeg.ts","../src/verify/media.ts","../src/audio/tts.ts","../src/audio/mux.ts","../src/verify/runner.ts","../src/verify/checks.ts","../src/verify/contact-sheet.ts","../src/verify/vision.ts","../src/verify/report.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { dirname, resolve as resolvePath } from 'node:path';\nimport { parseDocument, LineCounter, type Document } from 'yaml';\nimport { z } from 'zod';\nimport { specSchema, editDistance, type Spec } from './schema.js';\n\nexport class SpecError extends Error {\n constructor(\n message: string,\n public readonly issues: string[] = [],\n ) {\n super(message);\n }\n}\n\n/** Every key the schema knows, for \"did you mean\" suggestions on unrecognized keys. */\nconst KNOWN_KEYS = [\n 'playhead', 'title', 'subtitle', 'app', 'output', 'theme', 'masking', 'scenes', 'vars', 'extends', 'setup',\n 'url', 'viewport', 'storageState', 'compareUrl', 'assertLoggedIn', 'environment', 'network', 'dialogs', 'settle',\n 'timezone', 'locale', 'colorScheme', 'fixedTime', 'reducedMotion', 'block', 'stub', 'har', 'status', 'body', 'contentType', 'idleMs', 'capMs',\n 'kind', 'aspect', 'resolution', 'fps', 'pacing', 'dwellScale', 'audio', 'endCard',\n 'narration', 'provider', 'voice', 'rate', 'sfx', 'music', 'file', 'gainDb',\n 'accent', 'captions',\n 'target', 'style', 'id', 'steps', 'shot', 'timeout',\n 'goto', 'click', 'dblclick', 'hover', 'type', 'press', 'select', 'scroll', 'expect', 'wait',\n 'caption', 'focus', 'mask', 'text', 'value', 'keys', 'ms', 'by', 'visible', 'hidden', 'count',\n 'for', 'state', 'x', 'y', 'optional', 'clear', 'to', 'disabled', 'checked', 'rightclick', 'upload', 'drag',\n];\n\nfunction suggest(key: string): string | null {\n let best: string | null = null;\n let bestD = 3;\n for (const k of KNOWN_KEYS) {\n const d = editDistance(key.toLowerCase(), k.toLowerCase());\n if (d > 0 && d < bestD) {\n bestD = d;\n best = k;\n }\n }\n return best;\n}\n\n/**\n * Parse + validate YAML text into a Spec. Supports:\n * - `vars:` — `{{name}}` interpolation across every string in the spec; values may reference\n * the environment as `${env.NAME}` or `${env.NAME:-default}`. Unknown `{{var}}` is an error.\n * - line/column positions on every validation error (mapped back to the YAML source).\n * `extends:` requires file context — use loadSpec.\n */\nexport function parseSpec(yamlText: string, sourcePath = '<inline>'): Spec {\n const lineCounter = new LineCounter();\n const doc = parseDocument(yamlText, { lineCounter, keepSourceTokens: true });\n if (doc.errors.length > 0) {\n const first = doc.errors[0]!;\n throw new SpecError(`${sourcePath}: not valid YAML — ${first.message}`);\n }\n const raw = doc.toJS() as Record<string, unknown> | null;\n if (raw && typeof raw === 'object' && 'extends' in raw) {\n throw new SpecError(`${sourcePath}: \"extends\" needs a file on disk — load the spec with loadSpec/the CLI, not inline text`);\n }\n return validateResolved(interpolate(raw, sourcePath), sourcePath, doc, lineCounter);\n}\n\n/** Load a spec file, resolving `extends:` (base file merged under this one) and `vars:`. */\nexport async function loadSpec(path: string): Promise<Spec> {\n const merged = await loadRaw(resolvePath(path), 0);\n // Re-parse the LEAF file for position mapping: merged keys that came from a base file simply\n // won't have positions, which is the honest best effort for multi-file specs.\n const text = await readFile(resolvePath(path), 'utf8');\n const lineCounter = new LineCounter();\n const doc = parseDocument(text, { lineCounter });\n // extends appends BASE scenes/masking first, so merged index i maps to leaf index i-offset.\n // Without this shift, error positions pointed at the WRONG lines of the child file — a\n // confidently wrong position is worse than none (round-2 audit).\n const leaf = (doc.toJS() ?? {}) as Record<string, unknown>;\n const arrLen = (v: unknown) => (Array.isArray(v) ? v.length : 0);\n const offsets = {\n scenes: arrLen((merged as Record<string, unknown>).scenes) - arrLen(leaf.scenes),\n masking: arrLen((merged as Record<string, unknown>).masking) - arrLen(leaf.masking),\n };\n return validateResolved(interpolate(merged, path), path, doc, lineCounter, offsets);\n}\n\n/** Read a YAML file to a plain object, recursively merging its `extends:` base underneath it. */\nasync function loadRaw(path: string, depth: number): Promise<Record<string, unknown>> {\n if (depth > 4) throw new SpecError(`${path}: extends chain deeper than 4 — check for a cycle`);\n const text = await readFile(path, 'utf8');\n const doc = parseDocument(text);\n if (doc.errors.length > 0) throw new SpecError(`${path}: not valid YAML — ${doc.errors[0]!.message}`);\n const raw = (doc.toJS() ?? {}) as Record<string, unknown>;\n const base = raw.extends;\n delete raw.extends;\n if (base === undefined) return raw;\n if (typeof base !== 'string') throw new SpecError(`${path}: \"extends\" must be a path string`);\n const baseObj = await loadRaw(resolvePath(dirname(path), base), depth + 1);\n return mergeSpecs(baseObj, raw);\n}\n\n/** Merge rule: objects merge deep, scalars in the child win, `masking`/`scenes` arrays append\n * (base first), any other array is replaced by the child's. */\nfunction mergeSpecs(base: Record<string, unknown>, child: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...base };\n for (const [k, v] of Object.entries(child)) {\n const b = out[k];\n if (Array.isArray(b) && Array.isArray(v) && (k === 'masking' || k === 'scenes')) {\n out[k] = [...b, ...v];\n } else if (isPlainObject(b) && isPlainObject(v)) {\n out[k] = mergeSpecs(b, v);\n } else {\n out[k] = v;\n }\n }\n return out;\n}\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/** Resolve `vars:` (+ `${env.X[:-default]}` in their values) and interpolate `{{name}}` across\n * every string in the document. Fails loudly on an unknown var or unset env with no default —\n * a URL that silently renders \"undefined\" is worse than a parse error. */\nfunction interpolate(raw: unknown, sourcePath: string): unknown {\n if (!isPlainObject(raw)) return raw;\n const varsIn = isPlainObject(raw.vars) ? raw.vars : {};\n const vars = new Map<string, string>();\n for (const [name, value] of Object.entries(varsIn)) {\n vars.set(name, resolveEnv(String(value), sourcePath));\n }\n // Vars may reference other vars ({{host}} inside base:) — resolve iteratively, bounded, and\n // fail on a cycle. Round-2 audit: a one-pass resolve leaked literal \"{{host}}\" into URLs.\n for (let pass = 0; pass < 6; pass++) {\n let changed = false;\n for (const [name, value] of vars) {\n const next = value.replace(/\\{\\{\\s*([a-zA-Z0-9_.-]+)\\s*\\}\\}/g, (m, ref: string) => {\n if (ref === name) throw new SpecError(`${sourcePath}: variable {{${name}}} references itself`);\n const v = vars.get(ref);\n return v !== undefined && !v.includes(`{{${name}}}`) ? v : m;\n });\n if (next !== value) {\n vars.set(name, next);\n changed = true;\n }\n }\n if (!changed) break;\n if (pass === 5) throw new SpecError(`${sourcePath}: variable references did not resolve after 6 passes — circular vars?`);\n }\n // A cycle stabilizes without resolving (a↔b each still reference the other) — catch it here\n // rather than leaking literal {{refs}} into URLs and typed text.\n for (const [name, value] of vars) {\n const m = /\\{\\{\\s*([a-zA-Z0-9_.-]+)\\s*\\}\\}/.exec(value);\n if (m && vars.has(m[1]!)) {\n throw new SpecError(`${sourcePath}: circular variable reference — {{${name}}} and {{${m[1]}}} depend on each other`);\n }\n }\n const doc = { ...raw };\n delete doc.vars;\n\n const seen = (s: string): string => {\n const withEnv = resolveEnv(s, sourcePath);\n return withEnv.replace(/\\{\\{\\s*([a-zA-Z0-9_.-]+)\\s*\\}\\}/g, (_, name: string) => {\n const v = vars.get(name);\n if (v === undefined) {\n const near = suggest(name) ?? [...vars.keys()].find((k) => editDistance(k, name) <= 2);\n throw new SpecError(\n `${sourcePath}: unknown variable {{${name}}}${near ? ` — did you mean {{${near}}}?` : ''} (declared vars: ${[...vars.keys()].join(', ') || 'none'})`,\n );\n }\n return v;\n });\n };\n const walk = (v: unknown): unknown => {\n if (typeof v === 'string') return seen(v);\n if (Array.isArray(v)) return v.map(walk);\n if (isPlainObject(v)) return Object.fromEntries(Object.entries(v).map(([k, val]) => [k, walk(val)]));\n return v;\n };\n return walk(doc);\n}\n\n/** `${env.NAME}` / `${env.NAME:-default}` → the environment value (or default). */\nfunction resolveEnv(s: string, sourcePath: string): string {\n return s.replace(/\\$\\{env\\.([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\\}/g, (_, name: string, dflt?: string) => {\n const v = process.env[name];\n if (v !== undefined) return v;\n if (dflt !== undefined) return dflt;\n throw new SpecError(`${sourcePath}: environment variable ${name} is not set and has no default (use \\${env.${name}:-fallback})`);\n });\n}\n\ntype ArrayOffsets = { scenes: number; masking: number };\n\nfunction validateResolved(\n resolved: unknown,\n sourcePath: string,\n doc: Document,\n lineCounter: LineCounter,\n offsets: ArrayOffsets = { scenes: 0, masking: 0 },\n): Spec {\n const result = specSchema.safeParse(resolved);\n if (!result.success) {\n const issues = result.error.issues.map((iss) => formatIssue(iss, sourcePath, doc, lineCounter, offsets));\n throw new SpecError(`${sourcePath}: invalid spec\\n - ${issues.join('\\n - ')}`, issues);\n }\n return result.data;\n}\n\nfunction formatIssue(\n iss: z.core.$ZodIssue,\n sourcePath: string,\n doc: Document,\n lineCounter: LineCounter,\n offsets: ArrayOffsets = { scenes: 0, masking: 0 },\n): string {\n const where = iss.path.length ? humanPath(iss.path) : 'spec';\n const pos = positionOf(iss.path, doc, lineCounter, offsets);\n const at = pos ? `${sourcePath}:${pos.line}:${pos.col} ` : '';\n // Strict-mode \"unrecognized key\" errors get a nearest-known-key suggestion, so a typo like\n // `acent:` reads as \"did you mean accent?\" instead of a bare rejection.\n if (iss.code === 'unrecognized_keys') {\n const keys = (iss as { keys: string[] }).keys;\n const hints = keys\n .map((k) => ({ k, near: suggest(k) }))\n .map((h) => (h.near ? `\"${h.k}\" (did you mean \"${h.near}\"?)` : `\"${h.k}\"`))\n .join(', ');\n return `${at}${where}: unknown key${keys.length > 1 ? 's' : ''} ${hints}`;\n }\n return `${at}${where}: ${iss.message}`;\n}\n\n/** YAML source position for a Zod issue path (walking as deep as the leaf document allows). */\nfunction positionOf(\n path: PropertyKey[],\n doc: Document,\n lineCounter: LineCounter,\n offsets: ArrayOffsets = { scenes: 0, masking: 0 },\n): { line: number; col: number } | null {\n // With `extends`, merged array index i corresponds to leaf-file index i - offset; entries\n // contributed by the base file have NO position in this document — return none rather than\n // a wrong one.\n if ((path[0] === 'scenes' || path[0] === 'masking') && typeof path[1] === 'number') {\n const off = offsets[path[0] as 'scenes' | 'masking'];\n if (off > 0) {\n const adjusted = path[1] - off;\n if (adjusted < 0) return null;\n path = [path[0], adjusted, ...path.slice(2)];\n }\n }\n for (let depth = path.length; depth > 0; depth--) {\n try {\n const node = doc.getIn(path.slice(0, depth) as (string | number)[], true) as\n | { range?: [number, number, number] }\n | undefined;\n if (node?.range) {\n const pos = lineCounter.linePos(node.range[0]);\n return { line: pos.line, col: pos.col };\n }\n } catch {\n /* keep walking up */\n }\n }\n return null;\n}\n\nfunction humanPath(path: PropertyKey[]): string {\n // scenes.0.steps.2 → scenes[0].steps[2]\n return path\n .map((seg, i) => (typeof seg === 'number' ? `[${seg}]` : i === 0 ? String(seg) : `.${String(seg)}`))\n .join('');\n}\n","import { z } from 'zod';\nimport { parseLocator } from './locators.js';\n\n/** \"1280x800\" → {w, h} */\nconst dimensions = z\n .string()\n .regex(/^\\d+x\\d+$/, 'expected WIDTHxHEIGHT, e.g. 1280x800')\n .transform((s) => {\n const [w, h] = s.split('x').map(Number);\n return { w: w!, h: h! };\n });\n\nconst locatorString = z.string().min(1).superRefine((val, ctx) => {\n try {\n parseLocator(val);\n } catch (e) {\n ctx.addIssue({ code: 'custom', message: (e as Error).message });\n }\n});\n\nconst focusHint = z.union([z.literal('target'), z.literal('wide'), locatorString]);\n\n/** Per-step extras shared by every action. */\nconst EXTRA_KEYS = ['caption', 'narration', 'focus', 'mask', 'shot', 'timeout', 'optional'] as const;\n\n/** Common optional step fields. */\nconst stepExtras = {\n caption: z.string().optional(),\n /** The SPOKEN line for TTS narration — unconstrained by the caption card's size. Resolution:\n * spoken = narration ?? caption ?? auto; on-screen card = caption ?? auto. */\n narration: z.string().optional(),\n focus: focusHint.optional(),\n /** Camera-shot boundary control: 'cut' forces this step into its own shot; 'continue' merges\n * it into the previous shot even when the heuristic would split. Decouples camera cuts from\n * scene structure (scenes stay narrative). */\n shot: z.enum(['cut', 'continue']).optional(),\n /** Per-step budget override (ms) for finding the target / meeting the expectation. */\n timeout: z.number().int().positive().optional(),\n /** A failing optional step is SKIPPED (warned, unfilmed beat) instead of killing the whole\n * capture — for cookie banners, A/B'd tooltips, and other environment noise. */\n optional: z.boolean().optional(),\n};\n\nconst targetOrShorthand = z.union([\n locatorString,\n z.object({ target: locatorString, ...stepExtras }),\n]);\n\n// ---- normalized step forms (the discriminated union everything downstream consumes) ----\n\n// Every step variant is .strict(): an unknown field inside a step payload (a typo like `txet:`,\n// or a knob that doesn't exist like `zoom:`) must FAIL LOUDLY — silently dropping it makes a\n// misspelled option indistinguishable from a feature that works badly.\nconst gotoStep = z.object({ action: z.literal('goto'), url: z.string(), ...stepExtras }).strict();\nconst pointerStep = z\n .object({\n action: z.enum(['click', 'dblclick', 'hover']),\n target: locatorString,\n ...stepExtras,\n })\n .strict();\nconst typeStep = z\n .object({\n action: z.literal('type'),\n target: locatorString,\n text: z.string(),\n mask: z.boolean().default(false),\n /** Select-all + overwrite instead of appending — editing a pre-filled field without this\n * produces \"Janenew value\". */\n clear: z.boolean().default(false),\n ...stepExtras,\n })\n .strict();\nconst pressStep = z.object({ action: z.literal('press'), keys: z.string(), ...stepExtras }).strict();\nconst rightclickStep = z.object({ action: z.literal('rightclick'), target: locatorString, ...stepExtras }).strict();\n/** File upload via the input element — no native dialog is involved (or filmable). */\nconst uploadStep = z\n .object({ action: z.literal('upload'), target: locatorString, file: z.string(), ...stepExtras })\n .strict();\n/** Drag from one element to another (kanban cards, list reorder, sliders). */\nconst dragStep = z\n .object({ action: z.literal('drag'), target: locatorString, to: locatorString, ...stepExtras })\n .strict();\nconst selectStep = z\n .object({\n action: z.literal('select'),\n target: locatorString,\n value: z.string(),\n ...stepExtras,\n })\n .strict();\nconst scrollStep = z\n .object({\n action: z.literal('scroll'),\n target: locatorString.optional(),\n by: z.object({ x: z.number().default(0), y: z.number() }).strict().optional(),\n ...stepExtras,\n })\n .strict();\nconst expectStep = z\n .object({\n action: z.literal('expect'),\n target: locatorString.optional(),\n visible: z.boolean().optional(),\n text: z.string().optional(),\n /** Exact number of matching elements (e.g. rows in a filtered table). */\n count: z.number().int().min(0).optional(),\n /** Current page URL must CONTAIN this substring (or match when wrapped /like this/). */\n url: z.string().optional(),\n /** Form control's current value. */\n value: z.string().optional(),\n /** Element enabled/disabled and checked state. */\n disabled: z.boolean().optional(),\n checked: z.boolean().optional(),\n ...stepExtras,\n })\n .strict()\n .refine((s) => s.target !== undefined || s.url !== undefined, {\n message: 'expect needs a target locator (element assertions) and/or a url',\n })\n .refine((s) => s.target !== undefined || (s.visible === undefined && s.text === undefined && s.count === undefined && s.value === undefined && s.disabled === undefined && s.checked === undefined), {\n message: 'element assertions (visible/text/count/value/disabled/checked) need a target',\n });\n/** `wait: <ms>` is the discouraged blind sleep; `wait: { for: <locator>, state?, timeout? }`\n * is the structured form — wait until an element is visible/hidden, never a fixed nap. */\nconst waitStep = z\n .object({\n action: z.literal('wait'),\n ms: z.number().int().positive().optional(),\n for: locatorString.optional(),\n state: z.enum(['visible', 'hidden']).default('visible'),\n ...stepExtras,\n })\n .strict()\n .refine((s) => (s.ms !== undefined) !== (s.for !== undefined), {\n message: 'wait needs exactly one of `ms` (blind sleep, discouraged) or `for` (an element to wait on)',\n });\n\nexport const stepSchema = z.discriminatedUnion('action', [\n gotoStep,\n pointerStep,\n typeStep,\n pressStep,\n rightclickStep,\n uploadStep,\n dragStep,\n selectStep,\n scrollStep,\n expectStep,\n waitStep,\n]);\n\nexport type Step = z.infer<typeof stepSchema>;\n\n// ---- YAML authoring form: `- click: '...'` / `- type: { target, text }` with optional sibling keys ----\n\nconst ACTION_KEYS = ['goto', 'click', 'dblclick', 'hover', 'type', 'press', 'rightclick', 'upload', 'drag', 'select', 'scroll', 'expect', 'wait'] as const;\n\nconst authoredStep = z\n .record(z.string(), z.unknown())\n .superRefine((obj, ctx) => {\n const actions = ACTION_KEYS.filter((k) => k in obj);\n if (actions.length !== 1) {\n // Echo what the author actually wrote and suggest the nearest action — \"expected one of\n // ten actions\" with no mention of the offending key forces a by-eye diff of the file.\n const unknown = Object.keys(obj).filter((k) => !(EXTRA_KEYS as readonly string[]).includes(k));\n const hints = unknown\n .map((k) => ({ k, near: nearestAction(k) }))\n .filter((h): h is { k: string; near: string } => h.near !== null)\n .map((h) => ` — did you mean \"${h.near}\" instead of \"${h.k}\"?`)\n .join('');\n ctx.addIssue({\n code: 'custom',\n message:\n actions.length === 0\n ? `Step has no action (found: ${unknown.join(', ') || 'nothing'})${hints || ` — expected one of: ${ACTION_KEYS.join(', ')}`}`\n : `Step has multiple actions (${actions.join(', ')}) — exactly one is allowed`,\n });\n return;\n }\n const known = new Set<string>([...ACTION_KEYS, ...EXTRA_KEYS]);\n for (const key of Object.keys(obj)) {\n if (!known.has(key)) {\n ctx.addIssue({ code: 'custom', message: `Unknown step field \"${key}\"` });\n }\n }\n })\n .transform((obj) => normalizeStep(obj));\n\n/** Nearest valid action to a typo (edit distance ≤ 2), or null. */\nfunction nearestAction(key: string): string | null {\n let best: string | null = null;\n let bestD = 3;\n for (const a of ACTION_KEYS) {\n const d = editDistance(key.toLowerCase(), a);\n if (d < bestD) {\n bestD = d;\n best = a;\n }\n }\n return best;\n}\n\nexport function editDistance(a: string, b: string): number {\n const dp = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)] as number[]);\n for (let j = 0; j <= b.length; j++) dp[0]![j] = j;\n for (let i = 1; i <= a.length; i++) {\n for (let j = 1; j <= b.length; j++) {\n dp[i]![j] = Math.min(\n dp[i - 1]![j]! + 1,\n dp[i]![j - 1]! + 1,\n dp[i - 1]![j - 1]! + (a[i - 1] === b[j - 1] ? 0 : 1),\n );\n }\n }\n return dp[a.length]![b.length]!;\n}\n\nfunction normalizeStep(obj: Record<string, unknown>): unknown {\n const action = ACTION_KEYS.find((k) => k in obj)!;\n const payload = obj[action];\n const extras: Record<string, unknown> = {};\n for (const k of EXTRA_KEYS) {\n if (k in obj) extras[k] = obj[k];\n }\n\n if (typeof payload === 'string') {\n // shorthand value: locator for element actions, url for goto, keys for press\n if (action === 'goto') return { action, url: payload, ...extras };\n if (action === 'press') return { action, keys: payload, ...extras };\n return { action, target: payload, ...extras };\n }\n if (typeof payload === 'number' && action === 'wait') {\n return { action, ms: payload, ...extras };\n }\n if (payload !== null && typeof payload === 'object') {\n return { action, ...(payload as Record<string, unknown>), ...extras };\n }\n return { action, value: payload, ...extras };\n}\n\n// ---- top-level spec ----\n//\n// Every object here is .strict(): a key the schema doesn't know is an ERROR, never silently\n// dropped. The spec must mean what it says — an author must be able to tell \"I configured this\n// wrong\" apart from \"this configuration does nothing\".\n\nexport const specSchema = z\n .object({\n playhead: z.literal(1),\n title: z.string().min(1),\n /** Title-card subtitle. Defaults to the app's host — set this for anything shareable. */\n subtitle: z.string().optional(),\n app: z\n .object({\n url: z.string().url(),\n /** Capture viewport. When omitted it is derived from output.aspect so portrait/square\n * outputs are captured at a matching viewport (the app reflows natively, no cropping). */\n viewport: dimensions.optional(),\n storageState: z.string().optional(),\n /** Fail fast when auth is stale: this locator must match after the initial load, or the\n * capture aborts — instead of confidently filming the login page. */\n assertLoggedIn: locatorString.optional(),\n /** For before/after: a second app to capture the same flow against (the \"before\"). */\n compareUrl: z.string().url().optional(),\n /** Determinism controls: same spec → same pixels regardless of where/when it runs. */\n environment: z\n .object({\n timezone: z.string().optional(),\n locale: z.string().optional(),\n colorScheme: z.enum(['light', 'dark']).optional(),\n /** Freeze Date at this ISO timestamp — \"3 minutes ago\" stops drifting between runs. */\n fixedTime: z.string().optional(),\n reducedMotion: z.boolean().optional(),\n })\n .strict()\n .optional(),\n /** Request interception: block third-party noise, stub responses, replay a HAR. */\n network: z\n .object({\n block: z.array(z.string()).optional(),\n stub: z\n .array(\n z\n .object({\n url: z.string(),\n status: z.number().int().optional(),\n body: z.string().optional(),\n contentType: z.string().optional(),\n })\n .strict(),\n )\n .optional(),\n har: z.string().optional(),\n })\n .strict()\n .optional(),\n /** window.confirm()/alert() policy. Default accept — the silent auto-dismiss films the\n * cancel branch of confirm-guarded flows. */\n dialogs: z.enum(['accept', 'dismiss']).optional(),\n /** Settle tuning for slow backends / chatty apps. */\n settle: z\n .object({\n idleMs: z.number().int().positive().optional(),\n capMs: z.number().int().positive().optional(),\n })\n .strict()\n .optional(),\n })\n .strict(),\n output: z\n .object({\n kind: z\n .enum(['walkthrough', 'demo', 'bug-repro', 'before-after', 'release', 'social'])\n .default('walkthrough'),\n aspect: z.enum(['16:9', '9:16', '1:1']).default('16:9'),\n /** Output resolution; when omitted it is derived from the aspect. */\n resolution: dimensions.optional(),\n fps: z.number().int().min(24).max(60).default(30),\n pacing: z.enum(['relaxed', 'normal', 'brisk']).optional(),\n /**\n * Multiplier on per-step dwell (min-step duration, post-action holds, outro).\n * 1 = the pacing preset as-is. Raise it for long-form teaching walkthroughs\n * where each screen should linger so a viewer can read and absorb it.\n */\n dwellScale: z.number().min(0.5).max(4).optional(),\n /**\n * Audio. `narration: tts` speaks each step's caption (pacing grows so every line finishes\n * before its step ends). `sfx` adds a soft synthesized click at each click beat. `music`\n * lays a user-supplied bed under everything, ducked beneath narration. Any audio work\n * finishes with loudness normalization (EBU R128, I=-16).\n */\n audio: z\n .object({\n narration: z.enum(['none', 'tts']).default('none'),\n // 'say' — macOS built-in (zero deps, Mac-only, robotic).\n // 'kokoro' — natural neural voice, offline, cross-platform; needs the optional\n // kokoro-js package (npm i kokoro-js). Voices: af_heart (default), am_michael, …\n provider: z.enum(['say', 'kokoro']).default('say'),\n voice: z.string().optional(),\n rate: z.number().int().min(80).max(400).optional(),\n /** Click sound effects at click/select beats. Defaults on when this block is present. */\n sfx: z.boolean().default(true),\n /** Music bed from a local audio file (no asset is bundled — bring your own licensed track). */\n music: z\n .object({\n file: z.string(),\n gainDb: z.number().min(-40).max(6).default(-19),\n })\n .strict()\n .optional(),\n })\n .strict()\n // The kokoro voice set is deliberately limited to two curated, natural voices —\n // Heart (default) and Michael. Aliases 'heart'/'michael' are accepted.\n .refine(\n (a) =>\n a.provider !== 'kokoro' ||\n a.voice === undefined ||\n ['heart', 'af_heart', 'michael', 'am_michael'].includes(a.voice),\n { message: \"kokoro voice must be 'heart' (default) or 'michael'\", path: ['voice'] },\n )\n // `rate` means words-per-minute for `say` (~178) but playback speed ×100 for kokoro\n // (100 = normal). A say-tuned spec switched to kokoro would render 1.78× chipmunk —\n // catch it at parse time instead of at listen time.\n .refine((a) => a.provider !== 'kokoro' || a.rate === undefined || (a.rate >= 80 && a.rate <= 140), {\n message: 'kokoro rate is playback speed ×100 (100 = normal, sensible range 80–140) — a say-style words-per-minute value like 178 would speak absurdly fast',\n path: ['rate'],\n })\n .optional(),\n /** Closing card. When set, the video ends on a title-card-styled end card. */\n endCard: z\n .object({\n title: z.string().min(1),\n subtitle: z.string().optional(),\n })\n .strict()\n .optional(),\n })\n .strict()\n .prefault({}),\n // No `name` field: exactly one theme exists today, and a knob that is accepted but ignored is\n // a lie. It returns when a theme registry does.\n theme: z\n .object({\n accent: z\n .string()\n .regex(/^#[0-9a-fA-F]{6}$/, 'expected a #rrggbb hex color')\n .optional(),\n captions: z.enum(['bottom', 'top', 'off']).default('bottom'),\n })\n .strict()\n .prefault({}),\n masking: z\n .array(\n z\n .object({\n target: locatorString,\n style: z.enum(['solid', 'blur']).default('solid'),\n })\n .strict(),\n )\n .default([]),\n /** Steps that run BEFORE recording starts and never appear on film — dismiss a cookie-consent\n * banner, close a first-run tour, prime app state. Same step grammar as scenes. */\n setup: z.array(authoredStep.pipe(stepSchema)).default([]),\n scenes: z\n .array(\n z\n .object({\n id: z.string().regex(/^[a-z0-9][a-z0-9-]*$/, 'scene ids are lowercase kebab-case'),\n title: z.string().optional(),\n steps: z.array(authoredStep.pipe(stepSchema)).min(1),\n })\n .strict(),\n )\n .min(1)\n // Duplicate ids validated silently and then --from-scene picked whichever came first, and\n // stepRefs collided across scenes (round-2 audit) — especially easy to hit via `extends`.\n .superRefine((scenes, ctx) => {\n const seen = new Set<string>();\n scenes.forEach((s, i) => {\n if (seen.has(s.id)) {\n ctx.addIssue({ code: 'custom', path: [i, 'id'], message: `duplicate scene id \"${s.id}\" — ids must be unique (check the extended base spec too)` });\n }\n seen.add(s.id);\n });\n }),\n })\n .strict();\n\nexport type Spec = z.infer<typeof specSchema>;\nexport type Scene = Spec['scenes'][number];\nexport type OutputSettings = Spec['output'];\nexport type MaskRule = Spec['masking'][number];\nexport type OutputKind = Spec['output']['kind'];\nexport type Aspect = Spec['output']['aspect'];\n\n/** Capture viewport + output resolution for each aspect (portrait/square reflow, never crop). */\nexport const ASPECTS: Record<Aspect, { viewport: { w: number; h: number }; resolution: { w: number; h: number } }> = {\n '16:9': { viewport: { w: 1280, h: 720 }, resolution: { w: 1920, h: 1080 } },\n '9:16': { viewport: { w: 720, h: 1280 }, resolution: { w: 1080, h: 1920 } },\n '1:1': { viewport: { w: 900, h: 900 }, resolution: { w: 1080, h: 1080 } },\n};\n\n/** The capture viewport: explicit spec value, else derived from the output aspect. */\nexport function resolveViewport(spec: Spec): { w: number; h: number } {\n return spec.app.viewport ?? ASPECTS[spec.output.aspect].viewport;\n}\n\n/** The output resolution: explicit spec value, else derived from the aspect. */\nexport function resolveResolution(spec: Spec): { w: number; h: number } {\n return spec.output.resolution ?? ASPECTS[spec.output.aspect].resolution;\n}\n\n/** A step with its position in the spec — the unit the capture executor and compositor work in. */\nexport interface AddressedStep {\n sceneId: string;\n sceneIndex: number;\n stepIndex: number;\n /** Global 1-based index across all scenes, used for step numbering. */\n ordinal: number;\n step: Step;\n}\n\nexport function flattenSteps(spec: Spec): AddressedStep[] {\n const out: AddressedStep[] = [];\n let ordinal = 0;\n spec.scenes.forEach((scene, sceneIndex) => {\n scene.steps.forEach((step, stepIndex) => {\n ordinal += 1;\n out.push({ sceneId: scene.id, sceneIndex, stepIndex, ordinal, step });\n });\n });\n return out;\n}\n","/**\n * Playhead locator grammar — resilient, label/role-based element addressing.\n *\n * role=button[name=\"Add user\"] role + accessible name\n * role=cell[name=/api key/i] regex accessible name\n * label=Email form control by label\n * text=\"User added\" visible text\n * placeholder=Search input placeholder\n * testid=add-user data-testid\n * css=#legacy .thing escape hatch (warned)\n * ... >> nth=1 pick among multiple matches\n * frame=#preview >> role=button[name=\"Save\"] pierce into an iframe (chainable)\n * frame=iframe[name=a] >> frame=#inner >> text=\"Hi\" nested frames\n *\n * Parsed form is serializable (regexes stored as {source, flags}) so it can live\n * in spec.resolved.json and events.json.\n */\n\nexport interface RegexSpec {\n source: string;\n flags: string;\n}\n\nexport type TextMatch = { exact: string } | { substring: string } | { regex: RegexSpec };\n\nexport type LocatorBase =\n | { kind: 'role'; role: string; name?: TextMatch }\n | { kind: 'label'; match: TextMatch }\n | { kind: 'text'; match: TextMatch }\n | { kind: 'placeholder'; match: TextMatch }\n | { kind: 'testid'; value: string }\n | { kind: 'css'; selector: string };\n\nexport interface ParsedLocator {\n base: LocatorBase;\n nth?: number;\n /** CSS selectors of the iframe chain to pierce (outermost first) before resolving `base`. */\n frames?: string[];\n /** The original spec string, kept for captions/diagnostics. */\n raw: string;\n}\n\nexport class LocatorParseError extends Error {}\n\n/** Split on `>>` OUTSIDE quotes — a button named \"Continue >>\" must not shatter the locator\n * (round-2 audit: it did, and explore generated exactly such locators then crashed on them). */\nfunction splitSegments(raw: string): string[] {\n const parts: string[] = [];\n let cur = '';\n let quote: '\"' | \"'\" | null = null;\n for (let i = 0; i < raw.length; i++) {\n const ch = raw[i]!;\n if (quote) {\n cur += ch;\n if (ch === quote) quote = null;\n } else if (ch === '\"' || ch === \"'\") {\n quote = ch;\n cur += ch;\n } else if (ch === '>' && raw[i + 1] === '>') {\n parts.push(cur.trim());\n cur = '';\n i += 1;\n } else {\n cur += ch;\n }\n }\n parts.push(cur.trim());\n return parts;\n}\n\nexport function parseLocator(input: string): ParsedLocator {\n const raw = input.trim();\n let nth: number | undefined;\n\n // Segments: [frame=SEL ...] BASE [nth=N]\n const parts = splitSegments(raw);\n const frames: string[] = [];\n while (parts.length > 0 && parts[0]!.startsWith('frame=')) {\n const sel = unquote(parts.shift()!.slice('frame='.length).trim());\n if (!sel) throw new LocatorParseError(`Empty frame selector in \"${raw}\"`);\n frames.push(sel);\n }\n if (parts.length === 0) {\n throw new LocatorParseError(`Locator \"${raw}\" has frames but no element — add a base like role=... after the frame chain`);\n }\n const body = parts.shift()!;\n if (parts.length > 0) {\n const tail = parts.join(' >> ');\n const m = /^nth=(\\d+)$/.exec(tail);\n if (!m) throw new LocatorParseError(`Unsupported locator suffix \"${tail}\" in \"${raw}\" (only \"nth=N\" is supported)`);\n nth = Number(m[1]);\n }\n const withFrames = (p: ParsedLocator): ParsedLocator => (frames.length > 0 ? { ...p, frames } : p);\n\n const eq = body.indexOf('=');\n if (eq === -1) {\n throw new LocatorParseError(\n `Locator \"${raw}\" is missing an engine prefix — expected role=, label=, text=, placeholder=, testid= or css=`,\n );\n }\n const engine = body.slice(0, eq).trim();\n const rest = body.slice(eq + 1).trim();\n\n switch (engine) {\n case 'role': {\n const m = /^([\\w-]+)(?:\\[name=(.+)\\])?$/.exec(rest);\n if (!m) throw new LocatorParseError(`Malformed role locator \"${raw}\" — expected role=button[name=\"...\"]`);\n const base: LocatorBase = { kind: 'role', role: m[1]! };\n if (m[2] !== undefined) base.name = parseTextMatch(m[2]!, raw);\n return withFrames({ base, nth, raw });\n }\n case 'label':\n return withFrames({ base: { kind: 'label', match: parseTextMatch(rest, raw) }, nth, raw });\n case 'text':\n return withFrames({ base: { kind: 'text', match: parseTextMatch(rest, raw) }, nth, raw });\n case 'placeholder':\n return withFrames({ base: { kind: 'placeholder', match: parseTextMatch(rest, raw) }, nth, raw });\n case 'testid': {\n if (!rest) throw new LocatorParseError(`Empty testid in locator \"${raw}\"`);\n return withFrames({ base: { kind: 'testid', value: unquote(rest) }, nth, raw });\n }\n case 'css': {\n if (!rest) throw new LocatorParseError(`Empty css selector in locator \"${raw}\"`);\n return withFrames({ base: { kind: 'css', selector: rest }, nth, raw });\n }\n default:\n throw new LocatorParseError(\n `Unknown locator engine \"${engine}\" in \"${raw}\" — expected role, label, text, placeholder, testid or css`,\n );\n }\n}\n\nfunction parseTextMatch(s: string, context: string): TextMatch {\n const v = s.trim();\n if (v.startsWith('/')) {\n const m = /^\\/(.+)\\/([a-z]*)$/.exec(v);\n if (!m) throw new LocatorParseError(`Malformed regex \"${v}\" in locator \"${context}\"`);\n try {\n new RegExp(m[1]!, m[2]!);\n } catch {\n throw new LocatorParseError(`Invalid regex \"${v}\" in locator \"${context}\"`);\n }\n return { regex: { source: m[1]!, flags: m[2]! } };\n }\n if ((v.startsWith('\"') && v.endsWith('\"') && v.length >= 2) || (v.startsWith(\"'\") && v.endsWith(\"'\") && v.length >= 2)) {\n return { exact: v.slice(1, -1) };\n }\n if (!v) throw new LocatorParseError(`Empty text match in locator \"${context}\"`);\n return { substring: v };\n}\n\nfunction unquote(s: string): string {\n if ((s.startsWith('\"') && s.endsWith('\"')) || (s.startsWith(\"'\") && s.endsWith(\"'\"))) return s.slice(1, -1);\n return s;\n}\n\n/** Human-readable form of what a locator points at, used for captions when the accessible name is unavailable. */\nexport function locatorDisplayName(loc: ParsedLocator): string {\n const b = loc.base;\n switch (b.kind) {\n case 'role':\n return b.name ? textMatchDisplay(b.name) : b.role;\n case 'label':\n case 'text':\n case 'placeholder':\n return textMatchDisplay(b.match);\n case 'testid':\n return b.value;\n case 'css':\n return b.selector;\n }\n}\n\nfunction textMatchDisplay(m: TextMatch): string {\n if ('exact' in m) return m.exact;\n if ('substring' in m) return m.substring;\n return m.regex.source;\n}\n","import { join } from 'node:path';\nimport type { Spec, AddressedStep } from '../spec/schema.js';\nimport { flattenSteps, resolveViewport } from '../spec/schema.js';\nimport { parseLocator } from '../spec/locators.js';\nimport type { Driver, MaskInstruction } from './driver-api.js';\nimport { PlaywrightDriver } from './playwright-driver.js';\nimport type { ActionEvent, CaptureEvent, CursorWaypoint, EventLog, TargetInfo } from './events.js';\nimport { BundleWriter } from '../bundle/writer.js';\nimport { rectCenter, clamp, dist } from '../shared/geometry.js';\nimport { log } from '../shared/log.js';\nimport { FlowError } from '../shared/exit.js';\n\nexport interface CaptureOptions {\n outDir: string;\n headless?: boolean;\n captureFormat?: 'jpeg' | 'png';\n quality?: number;\n driver?: Driver;\n /**\n * Iteration accelerator: steps BEFORE this scene run fast (no cursor choreography, no\n * filming, no events) purely to build app state; capture starts at this scene. The bundle\n * is a partial covering only the filmed scenes — for iterating on one scene, not shipping.\n */\n fromScene?: string;\n}\n\nconst SETTLE = { idleMs: 300, capMs: 5000 };\nconst TARGET_TIMEOUT_MS = 10_000;\nconst EXPECT_TIMEOUT_MS = 10_000;\nconst TYPE_DELAY_MS = 45;\n/** Hard budget for one step end-to-end (resolve + cursor + action). A step that can't finish in\n * this window is failed with its stepRef instead of hanging the whole capture. */\nconst STEP_BUDGET_MS = 45_000;\n/** Watchdog: overall capture deadline. Long specs are bounded per-step anyway; this is the\n * backstop that guarantees a capture NEVER runs unbounded (the 7-minute-hang class). */\nconst CAPTURE_DEADLINE_MS = 10 * 60_000;\n\nexport async function capture(spec: Spec, opts: CaptureOptions): Promise<{ bundleDir: string }> {\n const bundleDir = join(opts.outDir, 'capture');\n const driver = opts.driver ?? new PlaywrightDriver();\n const dpr = 2;\n const format = opts.captureFormat ?? 'jpeg';\n const writer = new BundleWriter(bundleDir, format);\n const events: CaptureEvent[] = [];\n const maskRules: MaskInstruction[] = spec.masking.map((m) => ({\n loc: parseLocator(m.target),\n style: m.style,\n }));\n\n const viewport = resolveViewport(spec);\n const settleCfg = {\n idleMs: spec.app.settle?.idleMs ?? SETTLE.idleMs,\n capMs: spec.app.settle?.capMs ?? SETTLE.capMs,\n };\n log.info(`capturing \"${spec.title}\" from ${spec.app.url}`);\n await driver.launch({\n viewport,\n dpr,\n headless: opts.headless ?? true,\n ...(spec.app.storageState ? { storageStatePath: spec.app.storageState } : {}),\n ...(spec.app.environment ? { environment: spec.app.environment } : {}),\n ...(spec.app.network ? { network: spec.app.network } : {}),\n ...(spec.app.dialogs ? { dialogs: spec.app.dialogs } : {}),\n });\n\n // Clock scaffolding lives OUTSIDE the try so the finally can finalize the bundle: a failed\n // step must never destroy the footage already captured (the failure is when video evidence\n // matters most). t0 is re-based after clock sync below.\n let t0 = Date.now();\n const rel = (nodeMs: number) => nodeMs - t0;\n const now = () => rel(Date.now());\n let clockOffsetMs = 0;\n let failure: { stepRef: string; message: string } | undefined;\n let currentStepRef = '';\n\n try {\n clockOffsetMs = await driver.measureClockOffset();\n t0 = Date.now();\n\n // Pre-roll (--from-scene fast-forward) must leave NO events: navigations before filming\n // starts would give shot planning/verification events with no corresponding footage.\n let recordEvents = !opts.fromScene;\n driver.onNavigation((url, tNode) => {\n if (recordEvents) events.push({ type: 'navigation', url, t: rel(tNode) });\n });\n\n const startFilming = () =>\n driver.startCapture((frame) => writer.addFrame(frame.data, rel(frame.tNodeMs)), {\n format,\n quality: opts.quality ?? 82,\n scale: dpr,\n // The screencast source delivers paint-driven frames up to ~30fps during motion; the\n // paced screenshot fallback (PLAYHEAD_CAPTURE=screenshot) tops out ~20.\n fps: 30,\n });\n // Filming starts up-front normally, but AFTER any pre-roll: `setup:` steps (consent\n // banners, first-run tours) and --from-scene fast-forwarding build state and must never\n // appear on film.\n const preRoll = spec.setup.length > 0 || Boolean(opts.fromScene);\n if (!preRoll) await startFilming();\n\n // Initial navigation + masks. CSS-expressible rules also go in-page for continuous tagging,\n // so elements that appear MID-step get masked the frame they appear.\n await driver.installMaskRules(maskRules);\n await driver.goto(spec.app.url);\n await applyMasksAndSample(driver, maskRules, writer, now);\n await driver.settle(settleCfg);\n if (spec.app.assertLoggedIn) {\n // Fail FAST on stale auth instead of confidently filming the login page.\n await driver\n .expectState(parseLocator(spec.app.assertLoggedIn), { visible: true }, 8000)\n .catch(() => {\n throw new Error(\n `assertLoggedIn failed: ${spec.app.assertLoggedIn} not visible — storageState stale? Re-run: playhead login ${spec.app.url}`,\n );\n });\n }\n // Guarantee PRE-first-action footage: heavy initial loads can stall the first grabs (CDP\n // contention), and a first frame that lands after the first click makes the before-state\n // unprovable — for verification and for the viewer alike.\n if (!preRoll) await driver.captureNow();\n\n // Unfilmed setup: dismiss consent banners, close first-run tours, prime state. Runs with\n // the camera off; the first filmed frame shows the app already presentable.\n if (spec.setup.length > 0) {\n log.info(`running ${spec.setup.length} setup step(s) (state only, not filmed)`);\n for (const [i, s] of spec.setup.entries()) {\n currentStepRef = `setup/${i}`;\n await fastForwardStep(driver, s);\n }\n currentStepRef = '';\n }\n\n let steps = flattenSteps(spec);\n const totalSteps = steps.length;\n if (opts.fromScene) {\n const idx = steps.findIndex((s) => s.sceneId === opts.fromScene);\n if (idx < 0) throw new Error(`--from-scene: no scene with id \"${opts.fromScene}\" in the spec`);\n log.info(`fast-forwarding ${idx} step(s) to scene \"${opts.fromScene}\" (state only, not filmed)`);\n for (const pre of steps.slice(0, idx)) {\n currentStepRef = `${pre.sceneId}/${pre.stepIndex} (fast-forward)`;\n await fastForwardStep(driver, pre.step);\n }\n currentStepRef = '';\n steps = steps.slice(idx);\n }\n if (preRoll) {\n await driver.settle(settleCfg);\n recordEvents = true;\n await startFilming();\n await driver.captureNow();\n }\n\n for (const addressed of steps) {\n currentStepRef = `${addressed.sceneId}/${addressed.stepIndex}`;\n if (now() > CAPTURE_DEADLINE_MS) {\n throw new Error(`capture watchdog: exceeded ${CAPTURE_DEADLINE_MS / 60000} minutes at step ${currentStepRef}`);\n }\n log.step(`${addressed.ordinal}/${totalSteps} ${describeStep(addressed)}`);\n let event: ActionEvent;\n try {\n event = await withStepBudget(\n executeStep(driver, addressed, { rel, now }, spec.app.url),\n STEP_BUDGET_MS,\n currentStepRef,\n );\n } catch (e) {\n // `optional: true` = environment noise (cookie banner, A/B'd tooltip): skip the beat,\n // keep filming — one flaky pop-up must not cost a full re-run.\n if (addressed.step.optional) {\n log.warn(`optional step ${currentStepRef} skipped: ${(e as Error).message.split('\\n')[0]}`);\n continue;\n }\n throw e;\n }\n // Re-tag masks (new DOM may match rules), then settle.\n await applyMasksAndSample(driver, maskRules, writer, now);\n await driver.settle(settleCfg);\n // A focus HINT naming a third locator (\"click here, LOOK there\") points at the step's\n // PAYOFF — waiting for it is part of settling this step. Poll briefly: the payoff often\n // appears a beat after network-idle (the app's own mutation delay), and stamping tSettled\n // before it exists would freeze the hold on pre-payoff footage.\n const focus = 'focus' in addressed.step ? addressed.step.focus : undefined;\n if (focus && focus !== 'target' && focus !== 'wide') {\n const loc = parseLocator(focus);\n for (let i = 0; i < 10 && !event.focusTarget; i++) {\n event.focusTarget = await driver.tryMeasure(loc);\n if (!event.focusTarget) await sleep(250);\n }\n if (!event.focusTarget) {\n log.warn(`${addressed.sceneId}/${addressed.stepIndex}: focus locator never appeared: ${focus}`);\n }\n }\n await ensurePostActionFrame(driver, event.tAction, rel);\n // tSettled must point at a frame that reflects the settled state (payoff included).\n // captureNow above guarantees a fresh one, so stamp after it — even instant hash-route\n // navigations whose settle returned in ~100ms then have on-film proof of their effect.\n event.tSettled = now();\n if (event.targetPre && event.locator) {\n event.targetPost = await driver.tryMeasure(parseLocator(event.locator));\n }\n if (addressed.step.action === 'type' && addressed.step.mask && event.locator) {\n const info = await driver.tryMeasure(parseLocator(event.locator));\n if (info) writer.addMaskSample({ t: now(), rects: [{ style: 'solid', ...info.bbox }] });\n }\n events.push(event);\n }\n currentStepRef = '';\n\n // Trailing beat so the final state has footage to hold on.\n await driver.settle(settleCfg);\n await driver.captureNow();\n await sleep(400);\n return { bundleDir };\n } catch (e) {\n const message = (e as Error).message;\n failure = { stepRef: currentStepRef || '(setup)', message };\n // Failure diagnostics, best-effort: where we were and what the page looked like.\n try {\n const aria = await driver.ariaSnapshot();\n const url = driver.currentUrl();\n const { writeFile } = await import('node:fs/promises');\n await writeFile(\n join(bundleDir, 'failure.json'),\n JSON.stringify({ stepRef: failure.stepRef, message, url, at: new Date().toISOString() }, null, 2),\n );\n if (aria) await writeFile(join(bundleDir, 'failure-aria.txt'), aria);\n } catch {\n /* diagnostics are best-effort */\n }\n // A capture-time failure is the APP breaking the flow — exit code 1, not an infra error.\n throw new FlowError(\n `${message}\\n (partial bundle with ${writer.frameCount()} frames saved to ${bundleDir} — failure.json has the details)`,\n );\n } finally {\n // Finalize the bundle EVEN ON FAILURE: frames/index.json + manifest are what make the\n // captured footage openable, and a failed run's footage is the most valuable footage.\n await driver.stopCapture().catch(() => {});\n // Console/pageerror/dialog/popup evidence — what bug-repro needs and failure diagnosis reads.\n try {\n const consoleLog = driver.consoleLog();\n if (consoleLog.length > 0) {\n const { writeFile } = await import('node:fs/promises');\n await writeFile(\n join(bundleDir, 'console.json'),\n JSON.stringify(consoleLog.map((c) => ({ ...c, t: rel(c.t) })), null, 2),\n );\n }\n } catch {\n /* best-effort */\n }\n const durationMs = now();\n const eventLog: EventLog = {\n schema: 'playhead/events@1',\n meta: {\n viewport,\n dpr,\n frameW: 0, // finalized by writer from the first frame's real dimensions\n frameH: 0,\n clockOffsetMs,\n startedAtIso: new Date(t0).toISOString(),\n durationMs,\n appUrl: spec.app.url,\n },\n events,\n };\n try {\n const manifest = await writer.finish({\n spec,\n events: eventLog,\n appUrl: spec.app.url,\n viewport,\n dpr,\n clockOffsetMs,\n durationMs,\n ...(failure ? { partial: true, failure } : {}),\n });\n if (!failure) {\n log.ok(`bundle: ${manifest.frameCount} frames, ${(durationMs / 1000).toFixed(1)}s → ${bundleDir}`);\n } else {\n log.warn(`partial bundle: ${manifest.frameCount} frames up to ${failure.stepRef} → ${bundleDir}`);\n }\n } catch (finishErr) {\n log.warn(`could not finalize bundle: ${(finishErr as Error).message}`);\n }\n await driver.close();\n }\n}\n\n/** Advance app state with no filming, no cursor choreography, minimal waits (fast-forward\n * pre-roll for --from-scene). Blind `wait: ms` sleeps are skipped; expects are best-effort. */\nasync function fastForwardStep(driver: Driver, step: import('../spec/schema.js').Step): Promise<void> {\n const T = step.timeout ?? 8000;\n switch (step.action) {\n case 'goto':\n await driver.goto(step.url);\n break;\n case 'click':\n case 'dblclick': {\n // Real click even in pre-roll: a coordinate click silently redirected by a toast makes\n // the divergence surface steps later as a baffling locator failure.\n await driver.resolveTarget(parseLocator(step.target), T);\n await driver.actClick(parseLocator(step.target), { double: step.action === 'dblclick', timeoutMs: T });\n break;\n }\n case 'hover': {\n // Hover DOES have lasting state for hover-gated flows (nav menus) — skipping it made\n // `--from-scene` die on the very next click (round-2 audit).\n const t = await driver.resolveTarget(parseLocator(step.target), T);\n await driver.moveCursor(rectCenter(t.bbox), 60);\n break;\n }\n case 'type': {\n const t = await driver.resolveTarget(parseLocator(step.target), T);\n await driver.clickAt(rectCenter(t.bbox));\n await driver.typeText(step.text, 0);\n break;\n }\n case 'press':\n await driver.press(step.keys);\n break;\n case 'select':\n await driver.selectOption(parseLocator(step.target), step.value);\n break;\n case 'scroll':\n if (step.target) await driver.scrollIntoView(parseLocator(step.target));\n else if (step.by) await driver.scrollBy(step.by);\n await driver.waitForScrollSettle(1500);\n break;\n case 'rightclick': {\n await driver.resolveTarget(parseLocator(step.target), T);\n await driver.actClick(parseLocator(step.target), { button: 'right', timeoutMs: T });\n break;\n }\n case 'upload':\n await driver.setInputFiles(parseLocator(step.target), step.file);\n break;\n case 'drag':\n await driver.dragTo(parseLocator(step.target), parseLocator(step.to), T);\n break;\n case 'expect':\n await driver\n .expectState(\n step.target ? parseLocator(step.target) : null,\n { ...(step.visible !== undefined ? { visible: step.visible } : {}), ...(step.url !== undefined ? { url: step.url } : {}) },\n T,\n )\n .catch(() => {});\n break;\n case 'wait':\n if (step.for) {\n await driver.expectState(parseLocator(step.for), { visible: step.state !== 'hidden' }, T).catch(() => {});\n }\n break;\n }\n await driver.settle({ idleMs: 200, capMs: 2500 });\n}\n\n/** Fail a step with its ref when it exceeds the budget, instead of hanging the capture. */\nfunction withStepBudget<T>(p: Promise<T>, ms: number, stepRef: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new Error(`step ${stepRef} exceeded its ${ms / 1000}s budget`)),\n ms,\n );\n p.then(\n (v) => { clearTimeout(timer); resolve(v); },\n (e) => { clearTimeout(timer); reject(e); },\n );\n });\n}\n\ninterface Clock {\n rel: (nodeMs: number) => number;\n now: () => number;\n}\n\nasync function executeStep(driver: Driver, addressed: AddressedStep, clock: Clock, appUrl: string): Promise<ActionEvent> {\n const { step, sceneId, stepIndex, ordinal } = addressed;\n const base: ActionEvent = {\n type: 'action',\n kind: step.action,\n sceneId,\n stepIndex,\n ordinal,\n cursorPath: [],\n tStart: clock.now(),\n tAction: 0,\n tActionEnd: 0,\n tSettled: 0,\n ...(step.caption ? { caption: step.caption } : {}),\n ...(step.narration ? { narration: step.narration } : {}),\n ...(step.shot ? { shot: step.shot } : {}),\n ...('focus' in step && step.focus ? { focus: step.focus } : {}),\n };\n // Per-step override for target-resolution / expectation budgets.\n const budgetMs = step.timeout ?? TARGET_TIMEOUT_MS;\n\n switch (step.action) {\n case 'goto': {\n // Relative URLs resolve against app.url, so a spec can say `goto: /deals` and be pointed\n // at any environment by changing one line.\n const url = new URL(step.url, appUrl).href;\n base.locator = url;\n base.tAction = clock.now();\n await driver.goto(url);\n base.tActionEnd = clock.now();\n return base;\n }\n case 'click':\n case 'dblclick':\n case 'hover': {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n const pre = await driver.resolveTarget(loc, budgetMs);\n base.targetPre = pre;\n base.cursorPath = await moveToTarget(driver, pre, clock);\n if (step.action === 'hover') {\n base.tAction = clock.now();\n base.tActionEnd = base.tAction;\n } else {\n // Cosmetic cursor is already on the target; the ACTION goes through locator.click so\n // actionability + hit-target verification + retry come for free (a raw coordinate\n // click is silently redirected by anything drifting under the point).\n const { tDown, tUp } = await driver.actClick(loc, {\n double: step.action === 'dblclick',\n timeoutMs: budgetMs,\n });\n base.tAction = clock.rel(tDown);\n base.tActionEnd = clock.rel(tUp);\n }\n return base;\n }\n case 'type': {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n const pre = await driver.resolveTarget(loc, budgetMs);\n base.targetPre = pre;\n base.cursorPath = await moveToTarget(driver, pre, clock);\n await driver.actClick(loc, { timeoutMs: budgetMs });\n if (step.clear) {\n // Select-all so the typing OVERWRITES a pre-filled value instead of appending.\n await driver.press('ControlOrMeta+A');\n }\n if (step.mask) {\n // Tag before any keystroke lands; the overlay stays for the rest of the capture.\n await driver.setTypingMask(loc);\n }\n const { tFirst, tLast } = await driver.typeText(step.text, TYPE_DELAY_MS);\n base.tAction = clock.rel(tFirst);\n base.tActionEnd = clock.rel(tLast);\n base.masked = step.mask;\n base.typedText = step.mask ? '•'.repeat(Math.min(step.text.length, 8)) : step.text;\n return base;\n }\n case 'press': {\n base.locator = step.keys;\n const { tDown } = await driver.press(step.keys);\n base.tAction = clock.rel(tDown);\n base.tActionEnd = clock.now();\n return base;\n }\n case 'select': {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n const pre = await driver.resolveTarget(loc, budgetMs);\n base.targetPre = pre;\n base.cursorPath = await moveToTarget(driver, pre, clock);\n // No raw pre-click: it opens the native popup that nothing dismisses. selectOption\n // handles focus + change events; the cursor visit above supplies the visual beat.\n base.tAction = clock.now();\n await driver.selectOption(loc, step.value);\n base.typedText = step.value;\n base.tActionEnd = clock.now();\n return base;\n }\n case 'rightclick': {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n const pre = await driver.resolveTarget(loc, budgetMs);\n base.targetPre = pre;\n base.cursorPath = await moveToTarget(driver, pre, clock);\n const { tDown, tUp } = await driver.actClick(loc, { button: 'right', timeoutMs: budgetMs });\n base.tAction = clock.rel(tDown);\n base.tActionEnd = clock.rel(tUp);\n return base;\n }\n case 'upload': {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n // File inputs are routinely display:none — measure best-effort, never require visibility.\n base.targetPre = await driver.tryMeasure(loc);\n if (base.targetPre) base.cursorPath = await moveToTarget(driver, base.targetPre, clock);\n base.tAction = clock.now();\n await driver.setInputFiles(loc, step.file);\n base.typedText = step.file.split(/[\\\\/]/).pop() ?? step.file;\n base.tActionEnd = clock.now();\n return base;\n }\n case 'drag': {\n base.locator = step.target;\n const from = parseLocator(step.target);\n const to = parseLocator(step.to);\n const pre = await driver.resolveTarget(from, budgetMs);\n base.targetPre = pre;\n base.cursorPath = await moveToTarget(driver, pre, clock);\n const { tDown, tUp, path } = await driver.dragTo(from, to, budgetMs);\n // Append the pressed-drag waypoints so the film shows the full gesture.\n base.cursorPath = [...base.cursorPath, ...path.map((w) => ({ ...w, t: clock.rel(w.t) }))];\n base.tAction = clock.rel(tDown);\n base.tActionEnd = clock.rel(tUp);\n // Where did it land? The destination element is the step's payoff.\n base.targetPost = await driver.tryMeasure(to);\n return base;\n }\n case 'scroll': {\n base.tAction = clock.now();\n if (step.target) {\n base.locator = step.target;\n const loc = parseLocator(step.target);\n await driver.scrollIntoView(loc);\n await driver.waitForScrollSettle(2500); // measure only once the scroll has stopped\n base.targetPre = await driver.tryMeasure(loc);\n } else if (step.by) {\n await driver.scrollBy(step.by);\n await driver.waitForScrollSettle(2500);\n }\n base.tActionEnd = clock.now();\n return base;\n }\n case 'expect': {\n base.locator = step.target ?? step.url ?? '';\n const loc = step.target ? parseLocator(step.target) : null;\n await driver.expectState(\n loc,\n {\n ...(step.visible !== undefined ? { visible: step.visible } : {}),\n ...(step.text !== undefined ? { text: step.text } : {}),\n ...(step.count !== undefined ? { count: step.count } : {}),\n ...(step.url !== undefined ? { url: step.url } : {}),\n ...(step.value !== undefined ? { value: step.value } : {}),\n ...(step.disabled !== undefined ? { disabled: step.disabled } : {}),\n ...(step.checked !== undefined ? { checked: step.checked } : {}),\n },\n step.timeout ?? EXPECT_TIMEOUT_MS,\n );\n if (loc) base.targetPre = await driver.tryMeasure(loc);\n base.tAction = clock.now();\n base.tActionEnd = base.tAction;\n return base;\n }\n case 'wait': {\n base.tAction = clock.now();\n if (step.for) {\n // Structured wait: block on an element state instead of a blind sleep.\n base.locator = step.for;\n await driver.expectState(\n parseLocator(step.for),\n { visible: step.state !== 'hidden' },\n step.timeout ?? EXPECT_TIMEOUT_MS,\n );\n } else {\n await sleep(step.ms ?? 0);\n }\n base.tActionEnd = clock.now();\n return base;\n }\n }\n}\n\nasync function moveToTarget(driver: Driver, target: TargetInfo, clock: Clock): Promise<CursorWaypoint[]> {\n const to = rectCenter(target.bbox);\n const travel = clamp(250 + dist(driver.cursorPos(), to) * 0.5, 300, 700);\n const waypoints = await driver.moveCursor(to, travel);\n // Guarantee a frame of the EXACT state the user is about to act on. The paint-driven\n // screencast can throttle away the paint that produced this state (e.g. a suggestion\n // dropdown populating) and then go idle — the held frame would predate what's clicked\n // (user-reported: an empty dropdown on film while the click hits a real suggestion).\n await driver.captureNow();\n return waypoints.map((w) => ({ x: round1(w.x), y: round1(w.y), t: round1(clock.rel(w.t)) }));\n}\n\n/**\n * Guarantee a fresh frame reflecting the settled post-action state. Always captures one (not\n * only when footage looks stale): a fast hash-route navigation settles in ~100ms, and without a\n * forced post-settle frame the \"after\" sample can land on the pre-navigation paint.\n */\nasync function ensurePostActionFrame(\n driver: Driver,\n tAction: number,\n rel: (nodeMs: number) => number,\n): Promise<void> {\n await sleep(24); // let the post-action paint flush\n await driver.captureNow();\n if (rel(driver.lastFrameAt()) <= tAction) {\n for (let i = 0; i < 2 && rel(driver.lastFrameAt()) <= tAction; i++) {\n await sleep(40);\n await driver.captureNow();\n }\n if (rel(driver.lastFrameAt()) <= tAction) {\n log.warn(`no captured frame after action at t=${tAction.toFixed(0)}ms — footage may hold a stale frame`);\n }\n }\n}\n\nasync function applyMasksAndSample(\n driver: Driver,\n rules: MaskInstruction[],\n writer: BundleWriter,\n now: () => number,\n): Promise<void> {\n if (rules.length === 0) return;\n const rects = await driver.applyMasks(rules);\n if (rects.length > 0) writer.addMaskSample({ t: now(), rects });\n}\n\nfunction describeStep(a: AddressedStep): string {\n const s = a.step;\n switch (s.action) {\n case 'goto':\n return `goto ${s.url}`;\n case 'type':\n return `type into ${s.target}${s.mask ? ' (masked)' : ''}`;\n case 'press':\n return `press ${s.keys}`;\n case 'wait':\n return `wait ${s.ms}ms`;\n case 'scroll':\n return `scroll ${s.target ?? JSON.stringify(s.by)}`;\n default:\n return `${s.action} ${'target' in s ? s.target : ''}`;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction round1(n: number): number {\n return Math.round(n * 10) / 10;\n}\n","import { chromium, type Browser, type BrowserContext, type Page, type CDPSession, type Locator, type FrameLocator } from 'playwright';\nimport type {\n Driver,\n DriverLaunchOptions,\n MaskInstruction,\n RawInteractable,\n ScreencastFrame,\n ScreencastOptions,\n} from './driver-api.js';\nimport type { ParsedLocator, TextMatch } from '../spec/locators.js';\nimport type { TargetInfo, CursorWaypoint } from './events.js';\nimport type { Point } from '../shared/geometry.js';\nimport { minJerk } from '../shared/easing.js';\nimport { log } from '../shared/log.js';\nimport { InfraError } from '../shared/exit.js';\nimport { access } from 'node:fs/promises';\n\n/** Budget for a single input dispatch (mouse/keyboard) — these have no Playwright timeout of\n * their own and a wedged renderer otherwise blocks them forever. */\nconst INPUT_TIMEOUT_MS = 5000;\n\nconst MASK_INIT_SCRIPT = `\n(() => {\n if (window.__playheadMaskInstalled) return;\n window.__playheadMaskInstalled = true;\n // Each masked element gets its own overlay box parented into that element's own DOM subtree.\n // This is what makes masking survive the top layer: an element inside a <dialog> modal (or a\n // popover) paints above a document-level overlay, so the box must be a descendant of the same\n // top-layer subtree to cover it. A position:fixed box stays out of flow, so parenting it into a\n // flex/grid container does not disturb layout.\n const boxes = new Map();\n const base = (box) => {\n box.setAttribute('aria-hidden', 'true');\n box.style.position = 'fixed';\n box.style.pointerEvents = 'none';\n box.style.zIndex = '2147483647';\n box.style.borderRadius = '5px';\n box.style.margin = '0';\n };\n const sync = (box, el, style) => {\n const r = el.getBoundingClientRect();\n const pad = 3; // cover focus rings / borders just outside the element box\n box.style.left = (r.left - pad) + 'px';\n box.style.top = (r.top - pad) + 'px';\n box.style.width = (r.width + pad * 2) + 'px';\n box.style.height = (r.height + pad * 2) + 'px';\n box.style.display = r.width > 0 && r.height > 0 ? 'block' : 'none';\n if (style === 'blur') {\n box.style.backdropFilter = 'blur(18px)';\n box.style.webkitBackdropFilter = 'blur(18px)';\n box.style.background = 'rgba(120,124,140,0.45)';\n } else {\n box.style.backdropFilter = '';\n box.style.background = '#2a2f3a';\n }\n };\n // In-page rule matching: CSS-expressible mask rules (testid=, css=) are pushed into\n // window.__playheadMaskCssRules and re-scanned continuously, so an element that APPEARS\n // MID-STEP (a token in a modal, an email in a toast, a row from the fetch settle waits on)\n // is tagged the frame it appears — not seconds later at the next step boundary. Node-side\n // tagging remains the backstop for rules needing Playwright semantics (role/label/text).\n let scanTick = 0;\n // querySelectorAll does NOT pierce shadow roots — but Playwright's tagging does, so a masked\n // element inside a web component (any design system) would be tagged yet never overlaid,\n // filming the secret while masks.json claims coverage (round-2 audit). Walk shadow roots too.\n const deepQuery = (sel) => {\n const out = [];\n const walk = (root) => {\n try { for (const el of root.querySelectorAll(sel)) out.push(el); } catch (e) {}\n const all = root.querySelectorAll('*');\n for (const el of all) if (el.shadowRoot) walk(el.shadowRoot);\n };\n walk(document);\n return out;\n };\n const scanRules = () => {\n const rules = window.__playheadMaskCssRules || [];\n for (const r of rules) {\n try {\n for (const el of deepQuery(r.css)) {\n if (!el.hasAttribute('data-playhead-mask')) el.setAttribute('data-playhead-mask', r.style);\n }\n } catch (e) {}\n }\n };\n const tick = () => {\n try {\n if (scanTick++ % 3 === 0) scanRules(); // every ~3 frames — cheap, and a 1-frame leak beats a 1-step leak\n const tagged = new Set(deepQuery('[data-playhead-mask]'));\n for (const [el, box] of boxes) {\n if (!tagged.has(el) || !el.isConnected) { box.remove(); boxes.delete(el); }\n }\n for (const el of tagged) {\n const parent = el.parentElement || document.body;\n let box = boxes.get(el);\n if (!box) {\n box = document.createElement('div');\n base(box);\n parent.appendChild(box);\n boxes.set(el, box);\n } else if (box.parentElement !== parent) {\n parent.appendChild(box);\n }\n sync(box, el, el.getAttribute('data-playhead-mask'));\n }\n } catch (e) {}\n requestAnimationFrame(tick);\n };\n requestAnimationFrame(tick);\n})();\n`;\n\n/** In-page fallback accessible-name computation for when the CDP AX lookup fails. */\nconst FALLBACK_NAME_FN = `(el) => {\n const norm = (s) => (s || '').replace(/\\\\s+/g, ' ').trim();\n const label = el.getAttribute('aria-label');\n if (label) return norm(label);\n const labelledBy = el.getAttribute('aria-labelledby');\n if (labelledBy) {\n const parts = labelledBy.split(/\\\\s+/).map((id) => {\n const ref = document.getElementById(id);\n return ref ? ref.textContent : '';\n });\n const joined = norm(parts.join(' '));\n if (joined) return joined;\n }\n if (el.labels && el.labels.length) return norm(el.labels[0].textContent);\n if (el.alt) return norm(el.alt);\n const text = norm(el.textContent);\n if (text) return text.slice(0, 80);\n if (el.placeholder) return norm(el.placeholder);\n if (el.title) return norm(el.title);\n return null;\n}`;\n\n/** In-page: gather every interactable element with the fields needed to author a grounded locator. */\nconst COLLECT_INTERACTABLES_FN = `() => {\n const norm = (s) => (s || '').replace(/\\\\s+/g, ' ').trim();\n // Accessible text = visible text excluding aria-hidden / hidden subtrees, matching how the\n // ARIA name is computed (so a decorative icon inside a link doesn't leak into the name).\n const accText = (el) => {\n let t = '';\n const walk = (node) => {\n if (node.nodeType === 3) { t += node.textContent; return; }\n if (node.nodeType !== 1) return;\n if (node.getAttribute && (node.getAttribute('aria-hidden') === 'true' || node.hasAttribute('hidden'))) return;\n for (const c of node.childNodes) walk(c);\n };\n walk(el);\n return norm(t);\n };\n const IMPLICIT = { A: 'link', BUTTON: 'button', SELECT: 'combobox', TEXTAREA: 'textbox', SUMMARY: 'button' };\n const inputRole = (el) => {\n const t = (el.getAttribute('type') || 'text').toLowerCase();\n if (t === 'checkbox') return 'checkbox';\n if (t === 'radio') return 'radio';\n if (t === 'range') return 'slider';\n if (t === 'button' || t === 'submit' || t === 'reset') return 'button';\n if (t === 'search') return 'searchbox';\n return 'textbox';\n };\n const accName = (el) => {\n const al = el.getAttribute('aria-label'); if (al) return norm(al);\n const lb = el.getAttribute('aria-labelledby');\n if (lb) { const parts = lb.split(/\\\\s+/).map((id) => { const r = document.getElementById(id); return r ? r.textContent : ''; }); const j = norm(parts.join(' ')); if (j) return j; }\n if (el.labels && el.labels.length) return accText(el.labels[0]);\n if (el.alt) return norm(el.alt);\n // NEVER walk a <select>'s subtree: that concatenates every <option> into a monster\n // \"Choose option...grayrednavy…\" pseudo-name that no human would write as a locator.\n if (el.tagName === 'SELECT' || el.tagName === 'DATALIST') {\n const sel = el.selectedOptions && el.selectedOptions[0];\n return sel ? norm(sel.textContent) : null;\n }\n const txt = accText(el); if (txt) return txt.slice(0, 80);\n if (el.placeholder) return norm(el.placeholder);\n if (el.title) return norm(el.title);\n return null;\n };\n // Landmark region for catalog grouping: which part of the page the element lives in.\n const regionOf = (el) => {\n const lm = el.closest('[role=dialog], dialog, nav, [role=navigation], header, [role=banner], aside, [role=complementary], footer, [role=contentinfo], main, [role=main]');\n if (!lm) return 'page';\n const tag = lm.tagName.toLowerCase();\n const role = lm.getAttribute && lm.getAttribute('role');\n if (tag === 'dialog' || role === 'dialog') return 'dialog';\n if (tag === 'nav' || role === 'navigation') return 'nav';\n if (tag === 'header' || role === 'banner') return 'header';\n if (tag === 'aside' || role === 'complementary') return 'sidebar';\n if (tag === 'footer' || role === 'contentinfo') return 'footer';\n return 'main';\n };\n const sel = 'button, a[href], input, select, textarea, summary, [role=button], [role=link], [role=tab], [role=switch], [role=menuitem], [role=checkbox], [contenteditable=\"\"], [contenteditable=true], h1, h2, h3';\n const seen = new Set();\n const out = [];\n for (const el of document.querySelectorAll(sel)) {\n if (seen.has(el)) continue; seen.add(el);\n const r = el.getBoundingClientRect();\n const style = getComputedStyle(el);\n const visible = r.width > 1 && r.height > 1 && style.visibility !== 'hidden' && style.display !== 'none' &&\n r.bottom > 0 && r.top < innerHeight && r.right > 0 && r.left < innerWidth;\n const tag = el.tagName;\n const explicit = el.getAttribute('role');\n const role = explicit || IMPLICIT[tag] || (tag === 'INPUT' ? inputRole(el) : (tag[0] === 'H' && tag.length === 2 ? 'heading' : null));\n let label = null;\n if (el.labels && el.labels.length) label = norm(el.labels[0].textContent);\n const options = tag === 'SELECT' ? Array.from(el.options).map((o) => norm(o.textContent)) : undefined;\n out.push({\n tag, role,\n accessibleName: accName(el),\n label,\n placeholder: el.getAttribute && el.getAttribute('placeholder') ? norm(el.getAttribute('placeholder')) : null,\n testId: el.getAttribute && (el.getAttribute('data-testid') || el.getAttribute('data-test-id')) || null,\n text: accText(el).slice(0, 80) || null,\n bbox: { x: r.x, y: r.y, w: r.width, h: r.height },\n visible,\n inputType: tag === 'INPUT' ? (el.getAttribute('type') || 'text').toLowerCase() : (tag === 'SELECT' ? 'select' : null),\n region: regionOf(el),\n ...(options ? { options } : {}),\n });\n }\n return out;\n}`;\n\nexport class PlaywrightDriver implements Driver {\n private browser!: Browser;\n private context!: BrowserContext;\n private page!: Page;\n private cdp!: CDPSession;\n /** Dedicated CDP session for the capture loop so its screenshots never contend with the\n * executor's accessibility/geometry lookups on the main session (which could deadlock). */\n private captureCdp!: CDPSession;\n private cursor: Point = { x: 0, y: 0 };\n private navCallbacks: ((url: string, t: number) => void)[] = [];\n private captureActive = false;\n private captureLoop: Promise<void> | null = null;\n private captureOnFrame: ((f: ScreencastFrame) => void) | null = null;\n private captureOpts: ScreencastOptions | null = null;\n private inflightGrab: Promise<boolean> | null = null;\n private lastFrameNodeMs = 0;\n private clockOffset = 0;\n private tagCounter = 0;\n private typingMaskLoc: ParsedLocator | null = null;\n\n async launch(opts: DriverLaunchOptions): Promise<void> {\n // Preflight the browser binary: npm install never downloads it, so the most likely first-run\n // failure is \"no Chromium\". Fail as OUR infra error naming the one command that fixes it —\n // otherwise the user gets Playwright's generic banner, which suggests installing every\n // browser (~500MB) when chromium alone is needed. Guards every front door (CLI + MCP),\n // since this is the only file that launches a browser.\n try {\n await access(chromium.executablePath());\n } catch {\n throw new InfraError(\n 'Chromium is not installed (one-time setup) — run: npx playwright install chromium',\n );\n }\n const env = opts.environment;\n // Force the browser's REAL rasterization scale to match the emulated deviceScaleFactor:\n // this is what makes CDP screencast emit device pixels (2560-wide at dpr 2) instead of\n // CSS pixels — the paint-driven ~30fps source with full zoom headroom. Layout/CSS coords\n // are unaffected (verified: dpr, rects, viewport all unchanged). Screenshots then need\n // clip.scale divided by this factor, tracked as forcedDsf.\n this.forcedDsf = opts.dpr > 1 && process.env.PLAYHEAD_CAPTURE !== 'screenshot' ? opts.dpr : 1;\n this.browser = await chromium.launch({\n headless: opts.headless ?? true,\n ...(this.forcedDsf > 1 ? { args: [`--force-device-scale-factor=${this.forcedDsf}`] } : {}),\n });\n // Headless Chromium announces itself as \"HeadlessChrome/<version>\". Sites running UA-based\n // dynamic rendering (prerender middleware — a standard SEO setup for SPAs) respond to that\n // with the crawler snapshot: semantic HTML, no CSS, no app — and every downstream stage then\n // films the wrong product with full confidence. Present the exact reduced UA real Chrome\n // sends (frozen platform token, major version only, per Chrome's UA reduction), derived from\n // the actual browser version so it never drifts. Applied in headed mode too: capture must be\n // deterministic across modes.\n const chromeMajor = this.browser.version().split('.')[0] ?? this.browser.version();\n const uaPlatform =\n process.platform === 'darwin'\n ? 'Macintosh; Intel Mac OS X 10_15_7'\n : process.platform === 'win32'\n ? 'Windows NT 10.0; Win64; x64'\n : 'X11; Linux x86_64';\n this.context = await this.browser.newContext({\n userAgent: `Mozilla/5.0 (${uaPlatform}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeMajor}.0.0.0 Safari/537.36`,\n viewport: { width: opts.viewport.w, height: opts.viewport.h },\n deviceScaleFactor: opts.dpr,\n colorScheme: env?.colorScheme ?? 'light',\n ...(env?.timezone ? { timezoneId: env.timezone } : {}),\n ...(env?.locale ? { locale: env.locale } : {}),\n ...(env?.reducedMotion ? { reducedMotion: 'reduce' as const } : {}),\n ...(opts.storageStatePath ? { storageState: opts.storageStatePath } : {}),\n });\n this.context.setDefaultTimeout(10_000);\n this.context.setDefaultNavigationTimeout(20_000);\n\n // Network interception: blocked third-party noise, canned responses, HAR replay.\n const net = opts.network;\n if (net?.har) await this.context.routeFromHAR(net.har, { notFound: 'fallback' });\n for (const glob of net?.block ?? []) {\n await this.context.route(glob, (route) => route.fulfill({ status: 204, body: '' }));\n }\n for (const stub of net?.stub ?? []) {\n await this.context.route(stub.url, (route) =>\n route.fulfill({\n status: stub.status ?? 200,\n body: stub.body ?? '',\n contentType: stub.contentType ?? 'application/json',\n }),\n );\n }\n\n this.page = await this.context.newPage();\n if (env?.fixedTime) await this.page.clock.setFixedTime(new Date(env.fixedTime));\n await this.page.addInitScript(MASK_INIT_SCRIPT);\n this.cdp = await this.context.newCDPSession(this.page);\n this.captureCdp = await this.context.newCDPSession(this.page);\n this.page.on('framenavigated', (frame) => {\n if (frame === this.page.mainFrame()) {\n const t = Date.now();\n for (const cb of this.navCallbacks) cb(frame.url(), t);\n }\n });\n\n // Evidence + correctness listeners.\n this.page.on('console', (msg) => this.pushConsole(msg.type(), msg.text()));\n this.page.on('pageerror', (err) => this.pushConsole('pageerror', err.message));\n this.page.on('crash', () => {\n this.pushConsole('crash', 'page crashed');\n // Fail FAST: without this flag the capture dies slowly — screenshot loop churning CDP\n // session recreation and the step timing out 45s later with a generic message.\n this.crashed = true;\n });\n // Dialogs: Playwright's default DISMISSES, so a confirm()-guarded delete silently films the\n // cancel branch. Accept by default (spec-controllable), and always record it.\n const dialogPolicy = opts.dialogs ?? 'accept';\n this.page.on('dialog', (dialog) => {\n this.pushConsole('dialog', `${dialog.type()}(\"${dialog.message()}\") → ${dialogPolicy}`);\n void (dialogPolicy === 'accept' ? dialog.accept() : dialog.dismiss()).catch(() => {});\n });\n // Popups/new tabs: capture stays on the main page — record loudly instead of failing silently.\n this.context.on('page', (p) => {\n if (p !== this.page) {\n this.pushConsole('popup', `new tab/popup opened: ${p.url()} (not filmed — capture follows the main page)`);\n log.warn(`popup opened (${p.url()}) — multi-tab capture is not yet supported; footage stays on the main page`);\n }\n });\n\n this.cursor = { x: opts.viewport.w / 2, y: opts.viewport.h * 0.6 };\n await this.page.mouse.move(this.cursor.x, this.cursor.y);\n }\n\n private consoleBuf: { t: number; type: string; text: string }[] = [];\n /** Browser-level forced device scale (--force-device-scale-factor); 1 = not forced. */\n private forcedDsf = 1;\n private crashed = false;\n\n private assertAlive(): void {\n if (this.crashed) throw new Error('page crashed — the browser renderer died (see console.json)');\n }\n\n private pushConsole(type: string, text: string): void {\n this.consoleBuf.push({ t: Date.now(), type, text: text.slice(0, 500) });\n if (this.consoleBuf.length > 500) this.consoleBuf.shift();\n }\n\n consoleLog(): { t: number; type: string; text: string }[] {\n return [...this.consoleBuf];\n }\n\n async close(): Promise<void> {\n if (!this.browser) return;\n await withTimeout(this.browser.close(), 8000).catch(() => {});\n }\n\n async measureClockOffset(): Promise<number> {\n const samples: number[] = [];\n for (let i = 0; i < 5; i++) {\n const t0 = Date.now();\n const browserNow = await withTimeout(this.page.evaluate(() => Date.now()), 2000).catch(() => t0);\n const t1 = Date.now();\n samples.push(browserNow - (t0 + t1) / 2);\n }\n samples.sort((a, b) => a - b);\n this.clockOffset = samples[2]!;\n return this.clockOffset;\n }\n\n async goto(url: string): Promise<void> {\n await this.page.goto(url, { waitUntil: 'load' });\n // fonts.ready can stay pending FOREVER on a wedged dev server (one stalled font asset never\n // resolves the promise — .catch() only covers rejection). Race it in-page against a short\n // timer, and bound the evaluate itself so a blocked main thread can't hang the capture.\n await withTimeout(\n this.page.evaluate(\n () => Promise.race([(document as any).fonts?.ready, new Promise((r) => setTimeout(r, 2000))]),\n ),\n 3000,\n ).catch(() => {});\n }\n\n onNavigation(cb: (url: string, t: number) => void): void {\n this.navCallbacks.push(cb);\n }\n\n currentUrl(): string {\n return this.page.url();\n }\n\n async currentTitle(): Promise<string> {\n return this.page.title().catch(() => '');\n }\n\n async ariaSnapshot(): Promise<string> {\n return this.page.locator('body').ariaSnapshot().catch(() => '');\n }\n\n async countMatches(loc: ParsedLocator): Promise<number> {\n try {\n return await this.toLocator(loc).count();\n } catch {\n return 0;\n }\n }\n\n async collectInteractables(): Promise<RawInteractable[]> {\n const collect = new Function(`return (${COLLECT_INTERACTABLES_FN})()`) as () => RawInteractable[];\n const out = await withTimeout(this.page.evaluate(collect), 10_000).catch(() => [] as RawInteractable[]);\n\n // Pierce one level of iframes that have an addressable selector, so exploration SEES frame\n // content (a Storybook canvas, an embedded widget) and emits frame-qualified locators.\n const handles = await this.page.$$('iframe').catch(() => []);\n for (const h of handles) {\n try {\n const sel = await h.evaluate((el: HTMLIFrameElement) => {\n if (el.id) return `#${CSS.escape(el.id)}`;\n const name = el.getAttribute('name');\n if (name) return `iframe[name=\"${name}\"]`;\n const tid = el.getAttribute('data-testid');\n if (tid) return `iframe[data-testid=\"${tid}\"]`;\n return null;\n });\n if (!sel) continue;\n const frame = await h.contentFrame();\n if (!frame) continue;\n const rect = await h.boundingBox();\n const inner = await withTimeout(\n frame.evaluate(collect),\n 8000,\n ).catch(() => [] as RawInteractable[]);\n for (const e of inner) {\n out.push({\n ...e,\n framePrefix: `frame=${sel}`,\n bbox: rect ? { x: e.bbox.x + rect.x, y: e.bbox.y + rect.y, w: e.bbox.w, h: e.bbox.h } : e.bbox,\n });\n }\n } catch {\n /* cross-origin or detached frame — unexplorable, skip */\n }\n }\n return out;\n }\n\n // ---------- locating & measuring ----------\n\n private toLocator(loc: ParsedLocator): Locator {\n // Frame chain first: `frame=#preview >> role=...` pierces into the iframe(s). Page-level\n // locators pierce shadow DOM for free but NEVER iframes — this is what makes an app whose\n // content lives in a frame (Storybook canvases, embedded checkouts, MFEs) addressable.\n let scope: Page | FrameLocator = this.page;\n for (const sel of loc.frames ?? []) scope = scope.frameLocator(sel);\n const b = loc.base;\n let l: Locator;\n switch (b.kind) {\n case 'role':\n l = scope.getByRole(b.role as Parameters<Page['getByRole']>[0], b.name ? { name: toPw(b.name), exact: isExact(b.name) } : {});\n break;\n case 'label':\n l = scope.getByLabel(toPw(b.match), { exact: isExact(b.match) });\n break;\n case 'text':\n l = scope.getByText(toPw(b.match), { exact: isExact(b.match) });\n break;\n case 'placeholder':\n l = scope.getByPlaceholder(toPw(b.match), { exact: isExact(b.match) });\n break;\n case 'testid':\n l = scope.getByTestId(b.value);\n break;\n case 'css':\n l = scope.locator(b.selector);\n break;\n }\n if (loc.nth !== undefined) l = l.nth(loc.nth);\n return l;\n }\n\n async resolveTarget(loc: ParsedLocator, timeoutMs: number): Promise<TargetInfo> {\n this.assertAlive();\n const locator = this.toLocator(loc);\n try {\n await locator.waitFor({ state: 'visible', timeout: timeoutMs });\n } catch (e) {\n // Never collapse distinct failures into one string: an ambiguous locator (strict-mode\n // violation), a hidden-but-present element, and a genuinely missing element each need a\n // different fix from the author — say which one this is.\n const msg = (e as Error).message ?? '';\n if (/strict mode violation/i.test(msg)) {\n const count = await locator.count().catch(() => -1);\n throw new Error(\n `Locator is ambiguous: ${loc.raw} matches ${count >= 0 ? count : 'multiple'} elements — add '>> nth=N' to pick one`,\n );\n }\n const count = await this.countMatches(loc);\n const reason =\n count === 0\n ? 'no matching element on the page'\n : `${count} match(es) present but none became visible`;\n throw new Error(\n `Target not resolvable: ${loc.raw} — ${reason} within ${timeoutMs}ms on ${this.page.url()} (${firstLine(msg)})`,\n );\n }\n await locator.scrollIntoViewIfNeeded().catch(() => {});\n // Layout stability: two identical geometry samples one frame apart.\n const deadline = Date.now() + timeoutMs;\n let prev: string | null = null;\n while (Date.now() < deadline) {\n const box = await locator.boundingBox();\n const sig = box ? `${box.x},${box.y},${box.width},${box.height}` : null;\n if (sig && sig === prev) break;\n prev = sig;\n await this.nextFrame();\n }\n const info = await this.measure(locator, loc);\n if (!info) throw new Error(`Target disappeared while measuring: ${loc.raw}`);\n return info;\n }\n\n /** Wait for the page to paint one frame, bounded — a concurrent screenshot must never let this hang. */\n private async nextFrame(): Promise<void> {\n await withTimeout(\n this.page.evaluate(() => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)))),\n 1500,\n ).catch(() => {});\n }\n\n async tryMeasure(loc: ParsedLocator): Promise<TargetInfo | null> {\n const locator = this.toLocator(loc);\n try {\n if (!(await locator.isVisible())) return null;\n return await this.measure(locator, loc);\n } catch {\n return null;\n }\n }\n\n private async measure(locator: Locator, loc: ParsedLocator): Promise<TargetInfo | null> {\n const tag = `ph-${++this.tagCounter}`;\n const geom = await locator\n .evaluate((el, t) => {\n el.setAttribute('data-playhead-t', t);\n const r = el.getBoundingClientRect();\n return {\n bbox: { x: r.x, y: r.y, w: r.width, h: r.height },\n scroll: { x: window.scrollX, y: window.scrollY },\n };\n }, tag)\n .catch(() => null);\n if (!geom) return null;\n // Frame-scoped elements: getBoundingClientRect is relative to the FRAME's viewport, but\n // every consumer (camera, verification pixel sampling, click coordinates) works in MAIN\n // viewport space. locator.boundingBox() is main-frame-relative — use it for position.\n if (loc.frames && loc.frames.length > 0) {\n const box = await withTimeout(locator.boundingBox(), 3000).catch(() => null);\n if (box) geom.bbox = { x: box.x, y: box.y, w: box.width, h: box.height };\n // scroll must be the MAIN page's offsets (events.ts documents window scroll) — the\n // in-frame evaluate above read the iframe's own scroll (round-2 audit).\n const main = await withTimeout(this.page.evaluate(() => ({ x: window.scrollX, y: window.scrollY })), 2000).catch(() => null);\n if (main) geom.scroll = main;\n }\n\n let role: string | null = null;\n let name: string | null = null;\n try {\n const evalRes = (await withTimeout(\n this.cdp.send('Runtime.evaluate', {\n expression: `document.querySelector('[data-playhead-t=\"${tag}\"]')`,\n }),\n 4000,\n )) as { result: { objectId?: string } };\n if (evalRes.result.objectId) {\n const desc = (await withTimeout(\n this.cdp.send('DOM.describeNode', { objectId: evalRes.result.objectId }),\n 4000,\n )) as { node: { backendNodeId: number } };\n const ax = (await withTimeout(\n this.cdp.send('Accessibility.getPartialAXTree', {\n backendNodeId: desc.node.backendNodeId,\n fetchRelatives: false,\n }),\n 4000,\n )) as { nodes: { role?: { value?: string }; name?: { value?: string }; ignored?: boolean }[] };\n const node = ax.nodes?.[0];\n if (node && !node.ignored) {\n role = node.role?.value ?? null;\n name = node.name?.value ?? null;\n }\n await this.cdp.send('Runtime.releaseObject', { objectId: evalRes.result.objectId }).catch(() => {});\n }\n } catch (e) {\n log.debug(`AX lookup failed for ${loc.raw}: ${(e as Error).message}`);\n }\n if (!name) {\n name = await locator.evaluate(new Function('el', `return (${FALLBACK_NAME_FN})(el)`) as (el: Element) => string | null).catch(() => null);\n }\n await locator.evaluate((el) => el.removeAttribute('data-playhead-t')).catch(() => {});\n return { role, accessibleName: name, bbox: geom.bbox, scroll: geom.scroll };\n }\n\n // ---------- input ----------\n\n cursorPos(): Point {\n return { ...this.cursor };\n }\n\n async moveCursor(to: Point, durationMs: number): Promise<CursorWaypoint[]> {\n const from = { ...this.cursor };\n const waypoints: CursorWaypoint[] = [{ x: from.x, y: from.y, t: Date.now() }];\n const stepMs = 12;\n const steps = Math.max(2, Math.round(durationMs / stepMs));\n for (let i = 1; i <= steps; i++) {\n const p = minJerk(i / steps);\n const x = from.x + (to.x - from.x) * p;\n const y = from.y + (to.y - from.y) * p;\n // Input dispatch has no Playwright timeout and a wedged renderer can block it forever.\n await withTimeout(this.page.mouse.move(x, y), INPUT_TIMEOUT_MS);\n waypoints.push({ x, y, t: Date.now() });\n if (i < steps) await sleep(stepMs);\n }\n this.cursor = { ...to };\n return waypoints;\n }\n\n async clickAt(p: Point, opts?: { double?: boolean }): Promise<{ tDown: number; tUp: number }> {\n await withTimeout(this.page.mouse.move(p.x, p.y), INPUT_TIMEOUT_MS);\n this.cursor = { ...p };\n const tDown = Date.now();\n await withTimeout(this.page.mouse.down(), INPUT_TIMEOUT_MS);\n await sleep(70);\n await withTimeout(this.page.mouse.up(), INPUT_TIMEOUT_MS);\n if (opts?.double) {\n await sleep(60);\n await withTimeout(this.page.mouse.down({ clickCount: 2 }), INPUT_TIMEOUT_MS);\n await sleep(60);\n await withTimeout(this.page.mouse.up({ clickCount: 2 }), INPUT_TIMEOUT_MS);\n }\n return { tDown, tUp: Date.now() };\n }\n\n async typeText(text: string, delayMs: number): Promise<{ tFirst: number; tLast: number }> {\n const tFirst = Date.now();\n // Budget scales with the text: the typing itself takes length × delay by design.\n await withTimeout(this.page.keyboard.type(text, { delay: delayMs }), 10_000 + text.length * delayMs * 2);\n return { tFirst, tLast: Date.now() };\n }\n\n async press(keys: string): Promise<{ tDown: number }> {\n const tDown = Date.now();\n await withTimeout(this.page.keyboard.press(keys), INPUT_TIMEOUT_MS);\n return { tDown };\n }\n\n /**\n * The REAL click: Playwright's locator.click with actionability + hit-target verification and\n * retry. The cosmetic cursor has already animated to the target; this dispatches the action\n * through the checks a raw coordinate click bypasses (a toast/sticky header drifting under\n * the point between measure and click silently redirects a coordinate click).\n */\n async setInputFiles(loc: ParsedLocator, filePath: string): Promise<void> {\n await this.toLocator(loc).setInputFiles(filePath, { timeout: INPUT_TIMEOUT_MS * 2 });\n }\n\n /** Real drag: hover the source, press, glide to the destination in eased steps (recording\n * pressed-cursor waypoints for the film), release over the target's current position. */\n async dragTo(from: ParsedLocator, to: ParsedLocator, timeoutMs: number): Promise<{ tDown: number; tUp: number; path: CursorWaypoint[] }> {\n const src = this.toLocator(from);\n const dst = this.toLocator(to);\n await src.hover({ timeout: timeoutMs });\n const a = await src.boundingBox();\n if (!a) throw new Error(`drag source vanished: ${from.raw}`);\n const start = { x: a.x + a.width / 2, y: a.y + a.height / 2 };\n const tDown = Date.now();\n await withTimeout(this.page.mouse.down(), INPUT_TIMEOUT_MS);\n const path: CursorWaypoint[] = [{ x: start.x, y: start.y, t: tDown }];\n // Re-measure the destination AFTER the press — drag sources often spawn placeholders that\n // shift layout the moment the drag starts.\n const b = await dst.boundingBox();\n if (!b) {\n await this.page.mouse.up().catch(() => {});\n throw new Error(`drag destination not found: ${to.raw}`);\n }\n const end = { x: b.x + b.width / 2, y: b.y + b.height / 2 };\n const STEPS = 24;\n for (let i = 1; i <= STEPS; i++) {\n const u = minJerk(i / STEPS);\n const p = { x: start.x + (end.x - start.x) * u, y: start.y + (end.y - start.y) * u };\n await withTimeout(this.page.mouse.move(p.x, p.y), INPUT_TIMEOUT_MS);\n path.push({ x: p.x, y: p.y, t: Date.now() });\n await sleep(18);\n }\n const tUp = Date.now();\n await withTimeout(this.page.mouse.up(), INPUT_TIMEOUT_MS);\n this.cursor = end;\n return { tDown, tUp, path };\n }\n\n async actClick(loc: ParsedLocator, opts?: { double?: boolean; button?: 'right'; timeoutMs?: number }): Promise<{ tDown: number; tUp: number }> {\n const locator = this.toLocator(loc);\n // Stamp tDown at the REAL mousedown, not before locator.click()'s actionability wait —\n // that wait can take seconds, and a pre-wait stamp desyncs click beats, SFX, and the\n // post-action-frame guarantee (round-2 audit). An element-scoped one-shot listener records\n // the browser-epoch pointerdown (works inside iframes too — it lives on the element).\n // Absorb the actionability wait NOW (hover runs the same visible/stable/hit-target checks\n // as click), then force a frame: the last stored frame before the pointerdown must show the\n // state the user acts on. Without this, click's own retries can run 600ms+ during which the\n // page repaints (Wikipedia's suggestion menu blinks closed mid-re-render) — and the lead-in\n // hold lands on a frame that contradicts the click (user-reported).\n await locator.hover({ timeout: opts?.timeoutMs ?? 10_000 }).catch(() => {});\n // The hover itself can kick off page work (Wikipedia prefetches the article under the\n // pointer) that stalls the renderer ~700ms — a screenshot taken mid-stall shows a stale\n // intermediate paint (the suggestion menu's re-render blink), and the click dispatch queues\n // behind the stall. Two rAFs = the renderer is presenting frames again. Bounded: a wedged\n // page costs 1.2s here, not forever.\n await withTimeout(\n this.page.evaluate(() => new Promise(requestAnimationFrame).then(() => new Promise(requestAnimationFrame))),\n 1200,\n ).catch(() => {});\n await this.captureNow();\n const before = Date.now();\n await locator\n .evaluate((el) => {\n const w = el.ownerDocument.defaultView as (Window & { __phTDown?: number | null }) | null;\n if (w) {\n w.__phTDown = null;\n el.addEventListener('pointerdown', () => (w.__phTDown = Date.now()), { once: true, capture: true });\n }\n })\n .catch(() => {});\n if (opts?.double) await locator.dblclick({ delay: 60, timeout: opts?.timeoutMs ?? 10_000 });\n else await locator.click({ delay: 70, timeout: opts?.timeoutMs ?? 10_000, ...(opts?.button ? { button: opts.button } : {}) });\n const tUp = Date.now();\n const browserTDown = await withTimeout(\n locator.evaluate((el) => (el.ownerDocument.defaultView as (Window & { __phTDown?: number | null }) | null)?.__phTDown ?? null),\n 1500,\n ).catch(() => null);\n // browser epoch → node epoch via the cached clock offset. Fallback (element re-rendered\n // between listener install and click, listener lost): just before the click's release —\n // still far closer to truth than the pre-wait stamp.\n const tDown = typeof browserTDown === 'number' ? browserTDown - this.clockOffset : Math.max(before, tUp - 90);\n return { tDown, tUp };\n }\n\n async selectOption(loc: ParsedLocator, value: string): Promise<void> {\n const locator = this.toLocator(loc);\n try {\n await locator.selectOption({ label: value });\n } catch {\n await locator.selectOption(value);\n }\n // Drop focus so the next step isn't fighting a :focus-visible state. NO Escape here:\n // selectOption is programmatic (no native popup ever opens), and Escape closes whatever\n // dialog/drawer the <select> lives in — filming the wrong flow (round-2 audit).\n await withTimeout(\n locator.evaluate((el) => (el as HTMLElement).blur?.()),\n 2000,\n ).catch(() => {});\n }\n\n async scrollIntoView(loc: ParsedLocator): Promise<void> {\n const locator = this.toLocator(loc);\n await withTimeout(\n locator.evaluate((el) => el.scrollIntoView({ behavior: 'smooth', block: 'center' })),\n 5000,\n );\n }\n\n async scrollBy(by: { x: number; y: number }): Promise<void> {\n await withTimeout(\n this.page.evaluate(({ x, y }) => window.scrollBy({ left: x, top: y, behavior: 'smooth' }), by),\n 5000,\n );\n }\n\n async waitForScrollSettle(timeoutMs: number): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n let prev = Number.NaN;\n let stable = 0;\n while (Date.now() < deadline) {\n // Bound the evaluate itself: the outer deadline is only consulted between iterations, so a\n // single evaluate blocked by a busy main thread would otherwise blow straight past it.\n const y = await withTimeout(this.page.evaluate(() => window.scrollY), 1500).catch(() => prev);\n if (y === prev) {\n if (++stable >= 2) return;\n } else {\n stable = 0;\n prev = y;\n }\n await sleep(60);\n }\n }\n\n async expectState(\n loc: ParsedLocator | null,\n opts: { visible?: boolean; text?: string; count?: number; url?: string; value?: string; disabled?: boolean; checked?: boolean },\n timeoutMs: number,\n ): Promise<void> {\n // URL assertion: substring, or /pattern/ regex form. Checked first (and alone when no\n // locator is given).\n if (opts.url !== undefined) {\n const want = opts.url;\n const matches = (u: string) => {\n const m = /^\\/(.+)\\/([a-z]*)$/.exec(want);\n return m ? new RegExp(m[1]!, m[2]).test(u) : u.includes(want);\n };\n const deadlineUrl = Date.now() + timeoutMs;\n while (!matches(this.page.url())) {\n if (Date.now() > deadlineUrl) {\n throw new Error(`Expectation not met for URL: expected ${want}, got ${this.page.url()}`);\n }\n await sleep(100);\n }\n if (!loc) return;\n }\n if (!loc) return;\n const locator = this.toLocator(loc);\n const deadline = Date.now() + timeoutMs;\n let lastErr = 'condition not met';\n while (Date.now() < deadline) {\n try {\n if (opts.count !== undefined) {\n const n = await locator.count();\n if (n === opts.count) return;\n lastErr = `expected ${opts.count} match(es), found ${n}`;\n await sleep(100);\n continue;\n }\n const visible = await locator.first().isVisible();\n if (opts.visible !== undefined && visible !== opts.visible) {\n lastErr = `expected visible=${opts.visible}, got ${visible}`;\n } else if (opts.value !== undefined) {\n const v = await locator.inputValue({ timeout: 1000 }).catch(() => null);\n if (v === opts.value) return;\n lastErr = `expected value ${JSON.stringify(opts.value)}, got ${JSON.stringify(v)}`;\n } else if (opts.disabled !== undefined) {\n const d = await locator.isDisabled({ timeout: 1000 }).catch(() => null);\n if (d === opts.disabled) return;\n lastErr = `expected disabled=${opts.disabled}, got ${d}`;\n } else if (opts.checked !== undefined) {\n const c = await locator.isChecked({ timeout: 1000 }).catch(() => null);\n if (c === opts.checked) return;\n lastErr = `expected checked=${opts.checked}, got ${c}`;\n } else if (opts.text !== undefined) {\n const content = visible ? await locator.first().innerText() : '';\n if (!content.includes(opts.text)) {\n lastErr = `expected text to include \"${opts.text}\"`;\n } else {\n return;\n }\n } else {\n return;\n }\n } catch (e) {\n lastErr = (e as Error).message;\n }\n await sleep(100);\n }\n throw new Error(`expect failed for ${loc.raw}: ${lastErr}`);\n }\n\n // ---------- settling ----------\n\n /** Open requests → their start time. Long-lived streams (HMR sockets, SSE, long-polls) stop\n * counting after LONG_REQUEST_MS so a dev server can't pin the settle at its cap forever. */\n private pending = new Map<unknown, number>();\n private lastNetActivity = 0;\n private netTrackingInstalled = false;\n\n private installNetTracking(): void {\n if (this.netTrackingInstalled) return;\n this.netTrackingInstalled = true;\n this.lastNetActivity = Date.now();\n const IGNORED_TYPES = new Set(['eventsource', 'websocket', 'ping']);\n this.page.on('request', (req) => {\n if (IGNORED_TYPES.has(req.resourceType())) return;\n this.pending.set(req, Date.now());\n this.lastNetActivity = Date.now();\n });\n const done = (req: unknown) => {\n if (this.pending.delete(req)) this.lastNetActivity = Date.now();\n };\n this.page.on('requestfinished', done);\n this.page.on('requestfailed', done);\n }\n\n private static readonly LONG_REQUEST_MS = 2000;\n\n async settle(opts: { idleMs: number; capMs: number }): Promise<void> {\n this.assertAlive();\n this.installNetTracking();\n const start = Date.now();\n // Network idle — counting only requests younger than LONG_REQUEST_MS, so persistent\n // streams don't hold the gate.\n let capped = true;\n while (Date.now() - start < opts.capMs) {\n const now = Date.now();\n let inflight = 0;\n for (const t of this.pending.values()) {\n if (now - t < PlaywrightDriver.LONG_REQUEST_MS) inflight += 1;\n }\n if (inflight === 0 && now - this.lastNetActivity >= opts.idleMs) {\n capped = false;\n break;\n }\n await sleep(30);\n }\n if (capped) log.debug(`settle hit its ${opts.capMs}ms cap — footage may include in-flight loading`);\n // Real quiescence: no DOM mutations for 250ms AND no running finite animations (infinite\n // spinners are excluded — they'd block forever and their looping is the state, not a\n // transition). Bounded: a busy page costs at most ~1.8s here.\n await withTimeout(\n this.page.evaluate(\n () =>\n new Promise<void>((resolve) => {\n const done = () => {\n obs.disconnect();\n resolve();\n };\n let timer: ReturnType<typeof setTimeout>;\n const arm = () => {\n clearTimeout(timer);\n timer = setTimeout(() => {\n const running = (document.getAnimations?.() ?? []).filter((a) => {\n const t = a.effect?.getTiming?.();\n return a.playState === 'running' && t && t.iterations !== Infinity;\n });\n if (running.length === 0) done();\n else arm();\n }, 250);\n };\n const obs = new MutationObserver(() => arm());\n obs.observe(document.documentElement, { subtree: true, childList: true, attributes: true, characterData: true });\n arm();\n setTimeout(done, 1500); // hard floor: never block longer than this\n }),\n ),\n 1800,\n ).catch(async (e: Error) => {\n // Navigation mid-settle destroys the execution context, which used to be swallowed —\n // settle() returned instantly and tSettled landed on a LOADING page (round-2 audit).\n // Wait for the new document and run the quiescence pass once more against it.\n if (/context.*destroyed|navigat/i.test(e.message ?? '')) {\n await this.page.waitForLoadState('load', { timeout: 5000 }).catch(() => {});\n await withTimeout(\n this.page.evaluate(\n () =>\n new Promise<void>((resolve) => {\n setTimeout(resolve, 400); // fresh document: give layout/paint a beat\n }),\n ),\n 1000,\n ).catch(() => {});\n }\n });\n // Final paint flush.\n await this.nextFrame();\n }\n\n async saveStorageState(path: string): Promise<void> {\n await this.context.storageState({ path });\n }\n\n // ---------- masking ----------\n\n /**\n * Install CSS-expressible mask rules for continuous in-page tagging (see MASK_INIT_SCRIPT).\n * Rules that can't be expressed as CSS (role/label/text) return false and stay Node-tagged.\n */\n async installMaskRules(rules: MaskInstruction[]): Promise<void> {\n const cssRules = rules\n .map((r) => ({ css: maskRuleToCss(r.loc), style: r.style }))\n .filter((r): r is { css: string; style: 'solid' | 'blur' } => r.css !== null);\n if (cssRules.length === 0) return;\n const payload = JSON.stringify(cssRules);\n // Init script → future documents (navigations); evaluate → the current one.\n await this.page.addInitScript(`window.__playheadMaskCssRules = ${payload};`);\n await withTimeout(\n this.page.evaluate((json) => ((window as any).__playheadMaskCssRules = JSON.parse(json)), payload),\n 3000,\n ).catch(() => {});\n }\n\n async applyMasks(\n rules: MaskInstruction[],\n ): Promise<{ style: 'solid' | 'blur'; x: number; y: number; w: number; h: number }[]> {\n const tagged: { style: 'solid' | 'blur'; x: number; y: number; w: number; h: number }[] = [];\n for (const rule of rules) {\n const locator = this.toLocator(rule.loc);\n // .all() (not a single-match locator) so rules matching many elements — e.g. every API-key\n // cell — are each tagged and measured, without tripping strict-mode.\n const all = await locator.all().catch(() => [] as Locator[]);\n for (const el of all) {\n const box = await el\n .evaluate((node, style) => {\n node.setAttribute('data-playhead-mask', style);\n const r = (node as HTMLElement).getBoundingClientRect();\n return { x: r.x, y: r.y, w: r.width, h: r.height };\n }, rule.style)\n .catch(() => null);\n if (box && box.w > 0 && box.h > 0) tagged.push({ style: rule.style, ...box });\n }\n }\n return tagged;\n }\n\n async setTypingMask(loc: ParsedLocator | null): Promise<void> {\n if (loc) {\n this.typingMaskLoc = loc;\n const locator = this.toLocator(loc);\n await locator.evaluate((el) => el.setAttribute('data-playhead-mask', 'solid')).catch(() => {});\n } else if (this.typingMaskLoc) {\n const locator = this.toLocator(this.typingMaskLoc);\n await locator.evaluate((el) => el.removeAttribute('data-playhead-mask')).catch(() => {});\n this.typingMaskLoc = null;\n }\n }\n\n // ---------- frame capture ----------\n //\n // Headless Chromium's CDP screencast is hard-locked to CSS-pixel resolution and ignores\n // deviceScaleFactor, so a paced Page.captureScreenshot loop with clip.scale is what actually\n // yields 2x frames (the zoom headroom the camera planner needs).\n\n private screencastActive = false;\n\n async startCapture(onFrame: (f: ScreencastFrame) => void, opts: ScreencastOptions): Promise<void> {\n this.captureOnFrame = onFrame;\n this.captureOpts = opts;\n this.captureActive = true;\n\n // PRIMARY SOURCE: CDP Page.startScreencast — the compositor pushes a frame on every paint,\n // giving TRUE ~30fps during motion (typing, scrolling, animations) where the paced\n // screenshot loop topped out ~20 with 2-1-2 judder (round-2 audit's biggest craft gap).\n // Idle screens emit nothing, which the sparse timestamped bundle treats as holds — a fit\n // by design. captureNow() still forces screenshots for guaranteed post-action frames.\n // Escape hatch: PLAYHEAD_CAPTURE=screenshot restores the paced loop.\n if (process.env.PLAYHEAD_CAPTURE !== 'screenshot') {\n try {\n const vp = this.page.viewportSize() ?? { width: 1280, height: 720 };\n const expectedW = Math.round(vp.width * opts.scale);\n let sizeChecked = false;\n this.captureCdp.on('Page.screencastFrame', (ev: { data: string; sessionId: number; metadata?: { timestamp?: number } }) => {\n // Ack FIRST — a slow consumer must never stall the stream.\n void this.captureCdp.send('Page.screencastFrameAck', { sessionId: ev.sessionId }).catch(() => {});\n if (!this.captureActive || !this.captureOnFrame || !this.screencastActive) return;\n const data = Buffer.from(ev.data, 'base64');\n // FIRST-FRAME SIZE GATE: some Chromium builds emit screencast at CSS size, not device\n // pixels — a 1x stream would silently destroy the 2x zoom-headroom design. Detect it\n // and revert to the (slower but 2x) screenshot loop.\n if (!sizeChecked) {\n sizeChecked = true;\n const w = imageWidth(data, opts.format);\n if (w !== null && w < expectedW * 0.9) {\n log.warn(\n `screencast emits ${w}px-wide frames (need ${expectedW} for zoom headroom) — reverting to the 2x screenshot loop`,\n );\n this.screencastActive = false;\n void withTimeout(this.captureCdp.send('Page.stopScreencast'), 2000).catch(() => {});\n this.startScreenshotLoop(opts);\n return;\n }\n }\n // Browser wall-clock → node epoch via the cached offset; Date.now() as fallback.\n const tNodeMs = ev.metadata?.timestamp ? ev.metadata.timestamp * 1000 - this.clockOffset : Date.now();\n this.lastFrameNodeMs = tNodeMs;\n this.captureOnFrame({ data, tNodeMs });\n });\n await this.captureCdp.send('Page.startScreencast', {\n format: opts.format,\n quality: opts.quality,\n maxWidth: expectedW,\n maxHeight: Math.round(vp.height * opts.scale),\n // Compositor paints at up to ~60; halve toward the requested rate.\n everyNthFrame: Math.max(1, Math.round(60 / Math.max(15, opts.fps * 1.25))),\n });\n this.screencastActive = true;\n return;\n } catch (e) {\n log.warn(`screencast unavailable (${(e as Error).message.split('\\n')[0]}) — falling back to the paced screenshot loop`);\n }\n }\n\n this.startScreenshotLoop(opts);\n }\n\n private startScreenshotLoop(opts: ScreencastOptions): void {\n const intervalMs = 1000 / opts.fps;\n this.captureLoop = (async () => {\n while (this.captureActive) {\n const started = Date.now();\n await this.grabFrame();\n const elapsed = Date.now() - started;\n if (elapsed < intervalMs) await sleep(intervalMs - elapsed);\n }\n })();\n }\n\n /** Grab a frame, coalescing on any in-flight grab (so callers can await the current one).\n * Resolves true iff a frame was actually stored. */\n private grabFrame(): Promise<boolean> {\n if (this.inflightGrab) return this.inflightGrab;\n this.inflightGrab = this.doGrab().finally(() => {\n this.inflightGrab = null;\n });\n return this.inflightGrab;\n }\n\n private grabFailures = 0;\n\n private async doGrab(): Promise<boolean> {\n if (!this.captureOpts || !this.captureOnFrame) return false;\n try {\n const opts = this.captureOpts;\n const vp = this.page.viewportSize() ?? { width: 1280, height: 720 };\n // The screenshot clip is in PAGE coordinates, so it must track the current scroll offset;\n // a fixed {0,0} clip captures document-top (scrolled out of view) as blank once the page\n // scrolls. Clipping to [scrollX, scrollY, vp] captures exactly the visible viewport, which\n // is also the space the event bounding boxes live in. Read the offset via getLayoutMetrics\n // (a native CDP call) rather than page JS, so it never contends with the page thread and\n // stall the capture loop during navigation.\n const scroll = await this.readScroll();\n // 1.5s budget: a stall costs one frame, not eighty. (Was 4s — during navigations that\n // produced measured 4-second frame voids at exactly the action beat.)\n const shot = (await withTimeout(\n this.captureCdp.send('Page.captureScreenshot', {\n format: opts.format,\n quality: opts.quality,\n // Under --force-device-scale-factor the surface is already scaled — divide it out\n // or screenshots come back double-scaled (5120-wide).\n clip: { x: scroll.x, y: scroll.y, width: vp.width, height: vp.height, scale: opts.scale / this.forcedDsf },\n captureBeyondViewport: false,\n }),\n 1500,\n )) as { data: string };\n const tNodeMs = Date.now();\n this.lastFrameNodeMs = tNodeMs;\n this.grabFailures = 0;\n this.captureOnFrame({ data: Buffer.from(shot.data, 'base64'), tNodeMs });\n return true;\n } catch (err) {\n log.debug(`frame grab failed: ${(err as Error).message.split('\\n')[0]}`);\n // withTimeout abandons but cannot cancel the CDP send, and Chromium serves a session's\n // sends IN ORDER — so a wedged screenshot head-of-line blocks every later grab on this\n // session. After consecutive failures, tear the session down and start a fresh one.\n this.grabFailures += 1;\n if (this.grabFailures >= 2) {\n try {\n await this.captureCdp.detach().catch(() => {});\n this.captureCdp = await this.context.newCDPSession(this.page);\n log.warn('capture: recreated CDP session after stalled screenshots');\n this.grabFailures = 0;\n } catch {\n /* context mid-navigation — next grab retries */\n }\n }\n return false;\n }\n }\n\n private async readScroll(): Promise<{ x: number; y: number }> {\n try {\n const m = (await withTimeout(this.captureCdp.send('Page.getLayoutMetrics'), 1500)) as {\n cssVisualViewport?: { pageX?: number; pageY?: number };\n visualViewport?: { pageX?: number; pageY?: number };\n };\n const vv = m.cssVisualViewport ?? m.visualViewport;\n return { x: Math.round(vv?.pageX ?? 0), y: Math.round(vv?.pageY ?? 0) };\n } catch {\n return { x: 0, y: 0 };\n }\n }\n\n async stopCapture(): Promise<void> {\n this.captureActive = false;\n if (this.screencastActive) {\n this.screencastActive = false;\n await withTimeout(this.captureCdp.send('Page.stopScreencast'), 2000).catch(() => {});\n }\n await this.captureLoop?.catch(() => {});\n this.captureLoop = null;\n }\n\n lastFrameAt(): number {\n return this.lastFrameNodeMs;\n }\n\n async captureNow(): Promise<void> {\n // Wait out any in-flight grab (it may predate the action), then force a guaranteed fresh one\n // that reflects the acted-on/settled state. A grab can fail FAST and silently (screenshot vs\n // screencast compositor race — observed intermittently right after Wikipedia's suggestion\n // menu re-rendered), so retry on the grab's OWN success, never on frame recency: a screencast\n // frame from 50ms ago is not the state this call was asked to pin down.\n if (this.inflightGrab) await this.inflightGrab.catch(() => false);\n for (let i = 0; i < 3; i++) {\n if (await this.grabFrame()) return;\n await sleep(120);\n }\n log.warn('captureNow: no frame stored after 3 attempts — footage may hold a stale state here');\n }\n}\n\nfunction toPw(m: TextMatch): string | RegExp {\n if ('exact' in m) return m.exact;\n if ('substring' in m) return m.substring;\n return new RegExp(m.regex.source, m.regex.flags);\n}\n\nfunction isExact(m: TextMatch): boolean {\n return 'exact' in m;\n}\n\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\n/** CSS selector for a mask rule when the locator engine is CSS-expressible; null otherwise. */\nfunction maskRuleToCss(loc: ParsedLocator): string | null {\n const b = loc.base;\n if (b.kind === 'css') return b.selector;\n if (b.kind === 'testid') return `[data-testid=${JSON.stringify(b.value)}]`;\n return null;\n}\n\nfunction firstLine(s: string): string {\n const line = s.split('\\n')[0] ?? '';\n return line.length > 160 ? `${line.slice(0, 159)}…` : line;\n}\n\n/** Reject if a promise (typically a CDP send) doesn't settle in time, so a stalled call can't freeze the pipeline. */\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`operation timed out after ${ms}ms`)), ms);\n p.then(\n (v) => {\n clearTimeout(timer);\n resolve(v);\n },\n (e) => {\n clearTimeout(timer);\n reject(e);\n },\n );\n });\n}\n\n/** Width from JPEG (SOF marker) or PNG (IHDR) bytes — cheap, no decoder. Null if unparsable. */\nfunction imageWidth(data: Buffer, format: 'jpeg' | 'png'): number | null {\n try {\n if (format === 'png') {\n return data.length >= 24 ? data.readUInt32BE(16) : null;\n }\n // JPEG: scan markers for SOF0-SOF3 (0xC0-0xC3); width is bytes 7-8 of the segment.\n let i = 2;\n while (i + 9 < data.length) {\n if (data[i] !== 0xff) return null;\n const marker = data[i + 1]!;\n if (marker >= 0xc0 && marker <= 0xc3) return data.readUInt16BE(i + 7);\n const len = data.readUInt16BE(i + 2);\n i += 2 + len;\n }\n return null;\n } catch {\n return null;\n }\n}\n","/** Cubic bezier easing (CSS-style: fixed endpoints (0,0) and (1,1)). Serializable by its four control values. */\nexport type BezierParams = [number, number, number, number];\n\nexport const EASE_ZOOM: BezierParams = [0.4, 0, 0.2, 1];\nexport const EASE_PAN: BezierParams = [0.3, 0, 0.15, 1];\n\n/** Evaluate a CSS cubic-bezier at progress t ∈ [0,1] (solves x(t)=t for the parameter, returns y). */\nexport function cubicBezier(p: BezierParams, t: number): number {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n const [x1, y1, x2, y2] = p;\n // Newton-Raphson on x(u) = t\n let u = t;\n for (let i = 0; i < 8; i++) {\n const x = bez(u, x1, x2) - t;\n if (Math.abs(x) < 1e-6) break;\n const dx = dbez(u, x1, x2);\n if (Math.abs(dx) < 1e-6) break;\n u -= x / dx;\n }\n return bez(Math.max(0, Math.min(1, u)), y1, y2);\n}\n\nfunction bez(u: number, a: number, b: number): number {\n const v = 1 - u;\n return 3 * v * v * u * a + 3 * v * u * u * b + u * u * u;\n}\n\nfunction dbez(u: number, a: number, b: number): number {\n const v = 1 - u;\n return 3 * v * v * a + 6 * v * u * (b - a) + 3 * u * u * (1 - b);\n}\n\n/** Minimum-jerk position profile: smooth human-like travel, s(0)=0, s(1)=1, zero velocity/acceleration at ends. */\nexport function minJerk(t: number): number {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n return t * t * t * (10 - 15 * t + 6 * t * t);\n}\n","import pc from 'picocolors';\n\nlet verbose = false;\n\nexport function setVerbose(v: boolean): void {\n verbose = v;\n}\n\n// ALL human logging goes to stderr: stdout belongs to machine output (--json, catalogs),\n// so `playhead render --json | jq` works without ANSI noise corrupting the payload.\nexport const log = {\n info(msg: string): void {\n console.error(pc.dim('[playhead]') + ' ' + msg);\n },\n step(msg: string): void {\n console.error(pc.cyan(' ▸ ') + msg);\n },\n ok(msg: string): void {\n console.error(pc.green(' ✓ ') + msg);\n },\n warn(msg: string): void {\n console.error(pc.yellow(' ⚠ ') + msg);\n },\n error(msg: string): void {\n console.error(pc.red(' ✗ ') + msg);\n },\n debug(msg: string): void {\n if (verbose) console.error(pc.dim(' · ' + msg));\n },\n};\n","/**\n * Typed exit codes — a CI pipeline must be able to tell WHICH kind of red this is:\n *\n * 0 pass — rendered and publishable\n * 1 flow failure — the APP broke the flow (locator gone, expect failed, step timeout);\n * a partial bundle + failure clip exist\n * 2 quality fail — the flow ran but the video failed verification (framing, captions, audio)\n * 3 infra failure — environment problems (browser/ffmpeg missing, launch failed)\n * 4 usage error — bad spec / bad arguments\n *\n * A test tool that can't distinguish \"your app is broken\" from \"the video is ugly\" from\n * \"the runner is misconfigured\" gets `|| true`'d. This is the contract that prevents that.\n */\nexport const EXIT = {\n OK: 0,\n FLOW: 1,\n QUALITY: 2,\n INFRA: 3,\n USAGE: 4,\n} as const;\n\n/** The app broke the scripted flow (capture-time step failure). */\nexport class FlowError extends Error {\n readonly exitCode = EXIT.FLOW;\n}\n\n/** Environment/tooling problem — nothing about the app or the spec. */\nexport class InfraError extends Error {\n readonly exitCode = EXIT.INFRA;\n}\n\n/** Classify an arbitrary thrown error into an exit code. SpecErrors are matched by name to\n * avoid a circular import with the spec parser. */\nexport function exitCodeFor(e: unknown): number {\n if (e && typeof e === 'object') {\n if ('exitCode' in e && typeof (e as { exitCode: unknown }).exitCode === 'number') {\n return (e as { exitCode: number }).exitCode;\n }\n if ((e as Error).name === 'SpecError' || e instanceof Object && (e as Error).constructor?.name === 'SpecError') {\n return EXIT.USAGE;\n }\n }\n return EXIT.INFRA;\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { createHash } from 'node:crypto';\nimport { join } from 'node:path';\nimport sharp from 'sharp';\nimport type { Spec } from '../spec/schema.js';\nimport type { EventLog } from '../capture/events.js';\nimport type { BundleManifest, FrameIndexEntry, MaskSample } from './types.js';\nimport { sha256Json } from './hash.js';\nimport { PLAYHEAD_VERSION } from '../shared/version.js';\nimport { log } from '../shared/log.js';\n\n\nexport class BundleWriter {\n private frames: FrameIndexEntry[] = [];\n private pendingWrites: Promise<unknown>[] = [];\n private maskSamples: MaskSample[] = [];\n private counter = 0;\n private failedFrames = new Set<string>();\n private writeError: Error | undefined;\n private ready: Promise<void>;\n\n constructor(\n private readonly dir: string,\n private readonly captureFormat: 'jpeg' | 'png',\n ) {\n this.ready = mkdir(join(dir, 'frames'), { recursive: true }).then(() => {});\n }\n\n /** Queue a frame write. `t` is capture-relative ms. Each frame's BYTES are hashed at write\n * time — the index entry carries the digest, so the framesIndex hash transitively covers\n * every pixel in the bundle. (Round-2 audit: filename+timestamp hashing left frame images\n * freely swappable under a passing attest.) */\n addFrame(data: Buffer, t: number): void {\n this.counter += 1;\n const name = `${String(this.counter).padStart(6, '0')}.${this.captureFormat === 'jpeg' ? 'jpg' : 'png'}`;\n this.frames.push({ f: name, t: round1(t), h: createHash('sha256').update(data).digest('hex') });\n this.pendingWrites.push(\n this.ready\n .then(() => writeFile(join(this.dir, 'frames', name), data))\n // A rejected write with no handler is a PROCESS-FATAL unhandled rejection minutes\n // later, destroying the whole bundle over one frame (round-2 audit). Record the loss,\n // drop the frame from the index at finish, keep capturing.\n .catch((e: Error) => {\n this.failedFrames.add(name);\n this.writeError ??= e;\n }),\n );\n }\n\n addMaskSample(sample: MaskSample): void {\n this.maskSamples.push(sample);\n }\n\n frameCount(): number {\n return this.counter;\n }\n\n async finish(meta: {\n spec: Spec;\n events: EventLog;\n appUrl: string;\n viewport: { w: number; h: number };\n dpr: number;\n clockOffsetMs: number;\n durationMs: number;\n partial?: boolean;\n failure?: { stepRef: string; message: string };\n }): Promise<BundleManifest> {\n await this.ready;\n await Promise.all(this.pendingWrites);\n if (this.failedFrames.size > 0) {\n this.frames = this.frames.filter((f) => !this.failedFrames.has(f.f));\n log.warn(`${this.failedFrames.size} frame write(s) failed (${this.writeError?.message?.split('\\n')[0]}) — those frames dropped from the index`);\n }\n this.frames.sort((a, b) => a.t - b.t);\n\n // Actual frame pixel size is the source of truth for frame-space scale.\n let frameW = meta.viewport.w * meta.dpr;\n let frameH = meta.viewport.h * meta.dpr;\n const first = this.frames[0];\n if (first) {\n const info = await sharp(join(this.dir, 'frames', first.f)).metadata();\n if (info.width && info.height) {\n frameW = info.width;\n frameH = info.height;\n }\n }\n\n // Finalize the EVENT LOG's frame dimensions too — consumers (the camera planner's\n // sharpness cap) read meta.frameW from events.json, and leaving the placeholder 0 there\n // silently disabled the deepest zoom quantums on every render.\n meta.events.meta.frameW = frameW;\n meta.events.meta.frameH = frameH;\n\n // SECURITY: the resolved spec carries the raw text of masked type-steps (passwords, API\n // keys). Redact them before the spec touches disk — the bundle is designed to be shared,\n // and the events log already promises \"the real string never enters any artifact\".\n // specHash is computed on the REDACTED form so hash and artifact always agree.\n const spec = redactMaskedText(meta.spec);\n\n const manifest: BundleManifest = {\n schema: 'playhead/bundle@1',\n playheadVersion: PLAYHEAD_VERSION,\n specHash: sha256Json(spec),\n appUrl: meta.appUrl,\n viewport: meta.viewport,\n dpr: meta.dpr,\n frameW,\n frameH,\n clockOffsetMs: meta.clockOffsetMs,\n frameCount: this.frames.length,\n durationMs: round1(meta.durationMs),\n createdAtIso: new Date().toISOString(),\n captureFormat: this.captureFormat,\n hashes: {\n events: sha256Json(meta.events),\n framesIndex: sha256Json(this.frames),\n },\n ...(meta.partial ? { partial: true } : {}),\n ...(meta.failure ? { failure: meta.failure } : {}),\n };\n\n await Promise.all([\n writeFile(join(this.dir, 'frames', 'index.json'), JSON.stringify(this.frames)),\n writeFile(join(this.dir, 'events.json'), JSON.stringify(meta.events, null, 2)),\n writeFile(join(this.dir, 'masks.json'), JSON.stringify(this.maskSamples, null, 2)),\n writeFile(join(this.dir, 'spec.resolved.json'), JSON.stringify(spec, null, 2)),\n writeFile(join(this.dir, 'manifest.json'), JSON.stringify(manifest, null, 2)),\n ]);\n return manifest;\n }\n}\n\n/** Deep-copy the spec with every masked type-step's text replaced by bullets. */\nfunction redactMaskedText(spec: Spec): Spec {\n const copy = JSON.parse(JSON.stringify(spec)) as Spec;\n for (const scene of copy.scenes) {\n for (const step of scene.steps) {\n if (step.action === 'type' && step.mask && step.text) step.text = '••••••••';\n }\n }\n return copy;\n}\n\nfunction round1(n: number): number {\n return Math.round(n * 10) / 10;\n}\n","import { createHash } from 'node:crypto';\nimport { createReadStream } from 'node:fs';\n\nexport function sha256Json(value: unknown): string {\n return createHash('sha256').update(JSON.stringify(value)).digest('hex');\n}\n\nexport function sha256File(path: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash('sha256');\n createReadStream(path)\n .on('data', (d) => hash.update(d))\n .on('end', () => resolve(hash.digest('hex')))\n .on('error', reject);\n });\n}\n","import { createRequire } from 'node:module';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { existsSync, readFileSync } from 'node:fs';\n\n/**\n * The ONE version source: this package's own package.json. Resolved by WALKING UP from the\n * current file until the package root is found — never by a fixed '../..' depth, because the\n * bundled entry points sit at different depths (dist/index.js vs dist/cli/index.js) and a\n * fixed depth crashed the published library entry on import (round-2 audit, shipped in 0.1.3).\n */\nfunction resolveOwnPackageJson(): { version: string } {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 6; i++) {\n const p = join(dir, 'package.json');\n if (existsSync(p)) {\n const pkg = JSON.parse(readFileSync(p, 'utf8')) as { name?: string; version?: string };\n // Only accept OUR package.json — a stray one in a parent dir must not win.\n if (pkg.name === 'playhead-cli' || pkg.name === 'playhead') return { version: pkg.version ?? '0.0.0' };\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n // Dev fallback (running from src/ via tsx): resolve through node's module machinery.\n try {\n return createRequire(import.meta.url)('../../package.json') as { version: string };\n } catch {\n return { version: '0.0.0' };\n }\n}\n\nexport const PLAYHEAD_VERSION: string = resolveOwnPackageJson().version;\n","/** Axis-aligned rectangle. Space is documented at each use site (viewport CSS px, frame px, or output px). */\nexport interface Rect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport function rectCenter(r: Rect): Point {\n return { x: r.x + r.w / 2, y: r.y + r.h / 2 };\n}\n\nexport function rectUnion(a: Rect, b: Rect): Rect {\n const x = Math.min(a.x, b.x);\n const y = Math.min(a.y, b.y);\n return {\n x,\n y,\n w: Math.max(a.x + a.w, b.x + b.w) - x,\n h: Math.max(a.y + a.h, b.y + b.h) - y,\n };\n}\n\nexport function padRect(r: Rect, pad: number): Rect {\n return { x: r.x - pad, y: r.y - pad, w: r.w + pad * 2, h: r.h + pad * 2 };\n}\n\n/** True when `inner` lies fully inside `outer`, with an optional margin inside `outer`. */\nexport function rectContains(outer: Rect, inner: Rect, margin = 0): boolean {\n return (\n inner.x >= outer.x + margin &&\n inner.y >= outer.y + margin &&\n inner.x + inner.w <= outer.x + outer.w - margin &&\n inner.y + inner.h <= outer.y + outer.h - margin\n );\n}\n\nexport function clamp(v: number, min: number, max: number): number {\n return v < min ? min : v > max ? max : v;\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function dist(a: Point, b: Point): number {\n return Math.hypot(a.x - b.x, a.y - b.y);\n}\n\n/**\n * Camera state on the source viewport plane. The visible window always has the\n * OUTPUT aspect ratio (width-anchored): zoom=1 shows the full viewport width,\n * with height vpW/zoom/outAspect — the camera pans vertically over pages taller\n * than 16:9 rather than distorting them.\n */\nexport interface CameraState {\n cx: number;\n cy: number;\n zoom: number;\n}\n\nexport interface CameraPlane {\n vpW: number;\n vpH: number;\n outW: number;\n outH: number;\n}\n\n/** The viewport-space rect visible at a camera state (output-aspect, width-anchored). */\nexport function visibleRect(cam: CameraState, plane: CameraPlane): Rect {\n const w = plane.vpW / cam.zoom;\n const h = (w * plane.outH) / plane.outW;\n return { x: cam.cx - w / 2, y: cam.cy - h / 2, w, h };\n}\n\n/** Minimum zoom that keeps the visible window inside a page of this height. */\nexport function minZoom(plane: CameraPlane): number {\n return Math.max(1, plane.vpW / ((plane.vpH * plane.outW) / plane.outH));\n}\n\n/** Clamp a camera so its visible rect stays inside the viewport. */\nexport function clampCamera(cam: CameraState, plane: CameraPlane): CameraState {\n const zoom = Math.max(cam.zoom, minZoom(plane));\n const w = plane.vpW / zoom;\n const h = (w * plane.outH) / plane.outW;\n return {\n zoom,\n cx: clamp(cam.cx, w / 2, plane.vpW - w / 2),\n cy: clamp(cam.cy, h / 2, plane.vpH - h / 2),\n };\n}\n\n/** Project a viewport-space rect into output space given a camera state. */\nexport function projectRect(r: Rect, cam: CameraState, plane: CameraPlane): Rect {\n const vis = visibleRect(cam, plane);\n const s = plane.outW / vis.w;\n return { x: (r.x - vis.x) * s, y: (r.y - vis.y) * s, w: r.w * s, h: r.h * s };\n}\n\n/** Project a viewport-space point into output space given a camera state. */\nexport function projectPoint(p: Point, cam: CameraState, plane: CameraPlane): Point {\n const vis = visibleRect(cam, plane);\n const s = plane.outW / vis.w;\n return { x: (p.x - vis.x) * s, y: (p.y - vis.y) * s };\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { BundleData, BundleManifest, FrameIndexEntry, MaskSample } from './types.js';\nimport type { EventLog } from '../capture/events.js';\n\nexport async function openBundle(dir: string): Promise<BundleData> {\n const [manifestRaw, eventsRaw, framesRaw, masksRaw] = await Promise.all([\n readFile(join(dir, 'manifest.json'), 'utf8'),\n readFile(join(dir, 'events.json'), 'utf8'),\n readFile(join(dir, 'frames', 'index.json'), 'utf8'),\n readFile(join(dir, 'masks.json'), 'utf8').catch(() => '[]'),\n ]);\n const manifest = JSON.parse(manifestRaw) as BundleManifest;\n if (manifest.schema !== 'playhead/bundle@1') {\n throw new Error(`Unsupported bundle schema \"${manifest.schema}\" in ${dir}`);\n }\n const events = JSON.parse(eventsRaw) as EventLog;\n const frames = JSON.parse(framesRaw) as FrameIndexEntry[];\n const maskSamples = JSON.parse(masksRaw) as MaskSample[];\n if (frames.length === 0) throw new Error(`Bundle ${dir} contains no frames`);\n return { dir, manifest, events, frames, maskSamples };\n}\n\n/** Index of the latest frame with t ≤ tMs (hold semantics); clamps to the first frame. */\nexport function frameIndexForTime(frames: FrameIndexEntry[], tMs: number): number {\n let lo = 0;\n let hi = frames.length - 1;\n if (tMs <= frames[0]!.t) return 0;\n if (tMs >= frames[hi]!.t) return hi;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (frames[mid]!.t <= tMs) lo = mid;\n else hi = mid - 1;\n }\n return lo;\n}\n\nexport function framePath(bundle: BundleData, index: number): string {\n return join(bundle.dir, 'frames', bundle.frames[index]!.f);\n}\n","import { join } from 'node:path';\nimport { writeFile } from 'node:fs/promises';\nimport type { BundleData } from '../bundle/types.js';\nimport type { Spec } from '../spec/schema.js';\nimport { resolveResolution } from '../spec/schema.js';\nimport { resolveTheme, type ResolvedTheme } from '../theme/index.js';\nimport type { ComposeDiagnostics, ComposeManifest, OutputProfile } from './types.js';\nimport { profileForAspect, withStage } from './types.js';\nimport { kindProfile } from './kinds.js';\nimport { buildTimeline, pacingConfig } from './timeline/pacing.js';\nimport { planCamera } from './camera/planner.js';\nimport { planCursor } from './cursor/path.js';\nimport { buildOverlays } from './overlays/build.js';\nimport { renderVideo } from './render/renderer.js';\nimport { sourceFrameGray, sourceRegionGray, meanAbsDiff } from '../verify/media.js';\nimport { frameIndexForTime } from '../bundle/reader.js';\nimport { registerFonts } from '../theme/index.js';\nimport { sha256File } from '../bundle/hash.js';\nimport { log } from '../shared/log.js';\nimport { actionEvents } from '../capture/events.js';\nimport { writeCaption, writeNarration, type StepTexts } from './captions.js';\nimport { flattenSteps } from '../spec/schema.js';\nimport { synthesizeNarration, type NarrationClip } from '../audio/tts.js';\nimport { mixAudio } from '../audio/mux.js';\n\nexport interface ComposeResult {\n videoPath: string;\n manifestPath: string;\n manifest: ComposeManifest;\n}\n\n/** Pure planning: bundle + spec + theme → compose manifest. No rendering. */\n/** Per-step caption/narration text from the LIVE spec, keyed by stepRef — so text edits are a\n * re-compose, never a re-capture. */\nexport function specStepTexts(spec: Spec): Map<string, StepTexts> {\n const map = new Map<string, StepTexts>();\n for (const a of flattenSteps(spec)) {\n const s = a.step;\n if (s.caption || s.narration) {\n map.set(`${a.sceneId}/${a.stepIndex}`, {\n ...(s.caption ? { caption: s.caption } : {}),\n ...(s.narration ? { narration: s.narration } : {}),\n });\n }\n }\n return map;\n}\n\nexport function plan(\n bundle: BundleData,\n spec: Spec,\n theme?: ResolvedTheme,\n profile?: OutputProfile,\n audioMs?: Map<string, number>,\n): ComposeManifest {\n registerFonts();\n const resolvedTheme = theme ?? resolveTheme(spec);\n const kind = kindProfile(spec.output.kind);\n let prof: OutputProfile =\n profile ?? profileForAspect(spec.output.aspect, resolveResolution(spec), spec.output.fps);\n // The stage (matte + card + browser chrome) is the produced look; bug-repro stays literal.\n if (kind.stage && !prof.stage) prof = withStage(prof, true, bundle.manifest.viewport.w / bundle.manifest.viewport.h);\n const diagnostics: ComposeDiagnostics = { overflows: [], cameraFallbacks: [], clockWarnings: [] };\n const cfg = pacingConfig(spec.output.pacing ?? kind.pacing, kind);\n // Long-form teaching dwell: stretch the min-step, per-action holds, and outro so\n // each screen lingers. Idle-gap trimming and title card stay fixed (they're not dwell).\n const dwell = spec.output.dwellScale;\n if (dwell && dwell !== 1) {\n cfg.minStepMs *= dwell;\n cfg.outroMs *= dwell;\n for (const k of Object.keys(cfg.holds) as (keyof typeof cfg.holds)[]) cfg.holds[k] *= dwell;\n }\n const timeline = buildTimeline(bundle.events, cfg, audioMs);\n\n // Closing card: a title-card-styled segment appended after the outro. NOT on a partial\n // (failed) capture: the failure card replaces it — with both, the end-card segment had no\n // overlay and rendered 2.4s of blank background (round-2 audit).\n const END_CARD_MS = 2400;\n if (spec.output.endCard && !bundle.manifest.partial) {\n const endStart = timeline.durationMs;\n timeline.segments.push({ kind: 'card', outStart: endStart, outEnd: endStart + END_CARD_MS, cardId: 'end' });\n timeline.durationMs += END_CARD_MS;\n }\n // FAILURE CLIP: a partial bundle (capture died mid-run) composes into a diagnosis — the\n // captured footage plays through, then holds on a red card naming the step and the error.\n // This is the artifact a red CI run hands the developer: watch what happened, not a stack line.\n const FAILURE_CARD_MS = 3200;\n if (bundle.manifest.partial && bundle.manifest.failure) {\n const failStart = timeline.durationMs;\n timeline.segments.push({ kind: 'card', outStart: failStart, outEnd: failStart + FAILURE_CARD_MS, cardId: 'failure' });\n timeline.durationMs += FAILURE_CARD_MS;\n }\n\n // Clock sanity: warn when the action beat has no frame within 150ms after it.\n for (const step of timeline.steps) {\n const hasFrame = bundle.frames.some((f) => f.t >= step.srcAction && f.t <= step.srcAction + 150);\n if (!hasFrame && step.kind !== 'wait' && step.kind !== 'expect') {\n diagnostics.clockWarnings.push(`${step.stepRef}: no source frame within 150ms after the action`);\n }\n }\n\n const camera = planCamera(timeline.steps, bundle.events, prof, timeline.durationMs, {\n emphasis: kind.cameraEmphasis,\n });\n diagnostics.cameraFallbacks.push(...camera.fallbacks);\n const cursor = planCursor(timeline.steps, bundle.events);\n\n // Cross-dissolve at scene boundaries: the old footage (held at its last frame) fades into the\n // new scene instead of a hard cut.\n const transitions: { tStart: number; tEnd: number; srcFrom: number }[] = [];\n for (let i = 1; i < timeline.steps.length; i++) {\n const prev = timeline.steps[i - 1]!;\n const cur = timeline.steps[i]!;\n if (cur.sceneId !== prev.sceneId) {\n // Anchor the dissolve at the END of the previous step's hold — where the held frame\n // still EQUALS srcFrom. Anchoring at cur.outStart (after the idle-gap footage) drew the\n // old scene's frame over already-changed content: a backward pop, then a dissolve\n // forward (round-2 audit).\n const tStart = prev.outEnd;\n const tEnd = Math.min(cur.outStart + 120, tStart + 340);\n transitions.push({ tStart, tEnd: Math.max(tEnd, tStart + 200), srcFrom: Math.max(0, prev.srcSettled - 1) });\n }\n }\n\n const subtitle = spec.subtitle ?? safeHost(bundle.manifest.appUrl);\n const sceneTitles = new Map(\n spec.scenes.filter((s) => s.title).map((s) => [s.id, s.title as string]),\n );\n const overlays = buildOverlays(\n timeline.steps,\n bundle.events,\n resolvedTheme,\n prof,\n spec.title,\n subtitle,\n cfg.titleCardMs,\n diagnostics,\n kind,\n sceneTitles,\n camera.keyframes,\n specStepTexts(spec),\n );\n if (spec.output.endCard && !bundle.manifest.partial) {\n const endStart = timeline.durationMs - END_CARD_MS;\n overlays.push({ kind: 'dip', tStart: endStart - 350, tEnd: endStart, direction: 'out' });\n overlays.push({\n kind: 'titleCard',\n cardId: 'end',\n title: spec.output.endCard.title,\n ...(spec.output.endCard.subtitle ? { subtitle: spec.output.endCard.subtitle } : {}),\n tStart: endStart,\n tEnd: timeline.durationMs,\n });\n }\n if (bundle.manifest.partial && bundle.manifest.failure) {\n const failStart = timeline.durationMs - FAILURE_CARD_MS;\n overlays.push({ kind: 'dip', tStart: failStart - 300, tEnd: failStart, direction: 'out' });\n overlays.push({\n kind: 'failureCard',\n stepRef: bundle.manifest.failure.stepRef,\n message: bundle.manifest.failure.message,\n tStart: failStart,\n tEnd: timeline.durationMs,\n });\n }\n\n const totalFrames = Math.ceil((timeline.durationMs / 1000) * prof.fps);\n return {\n schema: 'playhead/compose@1',\n profile: prof,\n viewport: bundle.manifest.viewport,\n durationMs: timeline.durationMs,\n totalFrames,\n segments: timeline.segments,\n camera: camera.keyframes,\n cursor: cursor.segments,\n ripples: cursor.ripples,\n overlays,\n ...(transitions.length > 0 ? { transitions } : {}),\n steps: timeline.steps,\n theme: resolvedTheme,\n diagnostics,\n bundleHashes: bundle.manifest.hashes,\n };\n}\n\n/**\n * Transient-frame exclusion. Between the cursor ARRIVING on a click target and the pointerdown\n * landing, a busy page can paint one misleading transient (observed on Wikipedia: hovering a\n * search suggestion kicks off an article prefetch that stalls the renderer ~700ms, during which\n * the suggestion menu paints CLOSED — then reopens unfilmed right at the click). If that blink is\n * the last frame before the beat, the lead-in holds footage that contradicts the click the viewer\n * is about to see. Playwright's actionability guarantees the target WAS visible at dispatch, so a\n * frame in (arrival, action] whose target region drastically differs from the arrival frame is a\n * transient — exclude it from composition (the bundle on disk keeps every frame; verification\n * still sees full truth) and hold the last frame that shows what was clicked.\n */\nconst BLINK_DIFF_MIN = 25; // mean |Δgray| over the target bbox — a vanished element, not a hover style\nasync function excludeTransientPreActionFrames(bundle: BundleData): Promise<{ bundle: BundleData; notes: string[] }> {\n const notes: string[] = [];\n const dpr = bundle.manifest.dpr;\n const excluded = new Set<number>();\n for (const e of actionEvents(bundle.events)) {\n if (e.kind !== 'click' && e.kind !== 'dblclick') continue;\n if (!e.targetPre || !e.cursorPath || e.cursorPath.length === 0) continue;\n const tArrive = e.cursorPath[e.cursorPath.length - 1]!.t;\n if (!(tArrive < e.tAction)) continue;\n const iArrive = frameIndexForTime(bundle.frames, tArrive);\n const iBeat = frameIndexForTime(bundle.frames, e.tAction);\n if (iBeat <= iArrive) continue;\n const b = e.targetPre.bbox;\n const region = { x: b.x * dpr, y: b.y * dpr, w: b.w * dpr, h: b.h * dpr };\n const ref = await sourceRegionGray(bundle, bundle.frames[iArrive]!.t, region);\n if (!ref) continue;\n for (let i = iArrive + 1; i <= iBeat; i++) {\n const cand = await sourceRegionGray(bundle, bundle.frames[i]!.t, region);\n if (!cand || cand.length !== ref.length) continue;\n if (meanAbsDiff(ref, cand) > BLINK_DIFF_MIN) {\n excluded.add(i);\n notes.push(\n `${e.sceneId}/${e.stepIndex}: frame ${bundle.frames[i]!.f} (t=${Math.round(bundle.frames[i]!.t)}) is a pre-click transient (target region contradicts the arrival frame) — excluded from composition`,\n );\n }\n }\n }\n if (excluded.size === 0) return { bundle, notes };\n return { bundle: { ...bundle, frames: bundle.frames.filter((_, i) => !excluded.has(i)) }, notes };\n}\n\n/**\n * In-step jump smoothing. An anchor click (TOC link, in-page nav) teleports the whole view in\n * ONE source frame — on film the content changes with no visible cause and the viewer loses the\n * thread (user-reported on the Wikipedia \"1 History\" click: History was collapsed, then the next\n * shot was mid-article with no bridge). Scene-boundary dissolves don't cover it: the jump lands\n * mid-step, at the beat. Detect it by pixel diff across the action moment and bridge it with a\n * short cross-dissolve from the pre-jump frame, reusing the transition renderer.\n *\n * Needs pixel reads (async), so it runs in compose() after the synchronous plan().\n */\nconst JUMP_DIFF_MIN = 18; // mean |Δgray| 0–255 over the whole downscaled frame — most of the view changed\nconst JUMP_DISSOLVE_MS = 360;\nasync function smoothJumpCuts(bundle: BundleData, manifest: ComposeManifest): Promise<void> {\n for (const s of manifest.steps) {\n if (s.kind !== 'click' && s.kind !== 'dblclick' && s.kind !== 'press' && s.kind !== 'select') continue;\n const before = await sourceFrameGray(bundle, Math.max(0, s.srcAction - 30), 320);\n const after = await sourceFrameGray(bundle, Math.min(s.srcAction + 700, s.srcSettled), 320);\n if (after.frameT <= before.frameT || after.data.length !== before.data.length) continue;\n if (meanAbsDiff(before.data, after.data) < JUMP_DIFF_MIN) continue;\n const tStart = s.outBeat + 60; // let the click ripple land first — the CAUSE stays visible\n const tEnd = Math.min(tStart + JUMP_DISSOLVE_MS, s.outEnd);\n // Skip if a scene-boundary dissolve already overlaps this window (renderer picks first match).\n if ((manifest.transitions ?? []).some((w) => tStart <= w.tEnd && tEnd >= w.tStart)) continue;\n manifest.transitions = manifest.transitions ?? [];\n manifest.transitions.push({ tStart, tEnd, srcFrom: before.frameT });\n }\n}\n\nexport interface ComposeOptions {\n outDir: string;\n fileName?: string;\n theme?: ResolvedTheme;\n profile?: OutputProfile;\n}\n\n/** Full composition: plan + render + write manifest. Never touches the live app. */\nexport async function compose(bundle: BundleData, spec: Spec, opts: ComposeOptions): Promise<ComposeResult> {\n // Voice narration (optional): synthesize each step's spoken line first, so pacing\n // can grow every step to fit it. TTS is local (macOS `say`) and cached in the bundle.\n const audioCfg = spec.output.audio;\n let narration: Map<string, NarrationClip> | undefined;\n let audioMs: Map<string, number> | undefined;\n let narrationDegraded: string | undefined;\n // The provenance voice: what actually speaks when none is specified (say→Samantha,\n // kokoro→heart) — never a cross-provider default. (Round-2 audit: kokoro renders were\n // attesting \"Samantha\" in the signed manifest.)\n const voiceLabel = audioCfg?.voice ?? (audioCfg?.provider === 'kokoro' ? 'heart' : 'Samantha');\n if (audioCfg && audioCfg.narration === 'tts') {\n const texts = specStepTexts(spec);\n const lines = actionEvents(bundle.events)\n .map((e) => {\n const ref = `${e.sceneId}/${e.stepIndex}`;\n return { stepRef: ref, text: writeNarration(e, texts.get(ref)) };\n })\n .filter((l): l is { stepRef: string; text: string } => typeof l.text === 'string' && l.text.length > 0);\n log.info(`synthesizing narration: ${lines.length} lines (${audioCfg.provider}, voice ${voiceLabel})`);\n try {\n narration = await synthesizeNarration(lines, audioCfg, join(opts.outDir, 'narration'));\n audioMs = new Map([...narration].map(([k, v]) => [k, v.durationMs]));\n } catch (e) {\n // A host without the TTS runtime must not kill the render — but the degrade must be\n // VERDICT-VISIBLE, not just a stderr line: the spec asked for narration and the video\n // won't have it, so the audio check fails and the run exits as a quality failure.\n narrationDegraded = (e as Error).message.split('\\n')[0] ?? 'TTS unavailable';\n log.warn(`narration unavailable on this host (${narrationDegraded}) — rendering WITHOUT voice; the audio check will FAIL`);\n narration = undefined;\n audioMs = undefined;\n }\n }\n\n const transient = await excludeTransientPreActionFrames(bundle);\n bundle = transient.bundle;\n const manifest = plan(bundle, spec, opts.theme, opts.profile, audioMs);\n manifest.diagnostics.clockWarnings.push(...transient.notes);\n await smoothJumpCuts(bundle, manifest);\n for (const w of manifest.diagnostics.clockWarnings) log.warn(w);\n for (const f of manifest.diagnostics.cameraFallbacks) log.warn(f);\n\n const videoPath = join(opts.outDir, opts.fileName ?? 'out.mp4');\n log.info(\n `composing ${(manifest.durationMs / 1000).toFixed(1)}s (${manifest.totalFrames} frames @ ${manifest.profile.fps}fps, ${manifest.profile.width}x${manifest.profile.height})`,\n );\n await renderVideo(bundle, manifest, videoPath);\n\n // Audio bed: narration + click SFX + (user-supplied) music, ducked and loudness-normalized.\n if (audioCfg && (narration || audioCfg.sfx || audioCfg.music)) {\n // Keystroke ticks live in each type step's NATURAL-RATE windows (the retimed head/tail);\n // the fast-forwarded middle stays silent by design.\n const keyBeats: number[] = [];\n if (audioCfg.sfx) {\n for (const s of manifest.steps) {\n if (s.kind !== 'type') continue;\n const headEnd = Math.min(s.outEnd, s.outBeat + 1150);\n for (let t = s.outBeat + 40; t < headEnd; t += 78 + ((t | 0) % 29)) keyBeats.push(t);\n }\n }\n const clips = await mixAudio(videoPath, manifest.steps, manifest.durationMs, {\n ...(narration ? { narration } : {}),\n ...(audioCfg.sfx ? { sfxBeats: manifest.ripples } : {}),\n ...(keyBeats.length > 0 ? { keyBeats } : {}),\n ...(audioCfg.music ? { music: audioCfg.music } : {}),\n cacheDir: join(opts.outDir, 'narration'),\n });\n if (narration) {\n manifest.audio = {\n narrated: true,\n provider: audioCfg.provider,\n voice: voiceLabel,\n lines: clips.length,\n clips,\n };\n }\n log.info(\n `✓ audio: ${clips.length} narration line(s)` +\n `${audioCfg.sfx ? `, ${manifest.ripples.length} click(s)` : ''}` +\n `${audioCfg.music ? ', music bed' : ''} → ${videoPath}`,\n );\n }\n // Record a TTS degrade in the manifest EVEN IF no audio bed ran at all — the verifier turns\n // this into a failing audio check instead of a silent skip.\n if (narrationDegraded && !manifest.audio) {\n manifest.audio = {\n narrated: false,\n provider: audioCfg?.provider ?? 'say',\n voice: voiceLabel,\n lines: 0,\n degraded: narrationDegraded,\n };\n } else if (narrationDegraded && manifest.audio) {\n manifest.audio.degraded = narrationDegraded;\n }\n\n manifest.videoSha256 = await sha256File(videoPath);\n const manifestPath = join(opts.outDir, 'compose-manifest.json');\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2));\n return { videoPath, manifestPath, manifest };\n}\n\nexport async function renderFromManifest(bundle: BundleData, manifest: ComposeManifest, videoPath: string): Promise<void> {\n await renderVideo(bundle, manifest, videoPath);\n}\n\nfunction safeHost(url: string): string {\n try {\n return new URL(url).host;\n } catch {\n return url;\n }\n}\n","import { existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { createRequire } from 'node:module';\nimport { GlobalFonts } from '@napi-rs/canvas';\nimport type { Spec } from '../spec/schema.js';\n\nexport interface ResolvedTheme {\n name: string;\n /** Accent color for cursor ripple, badges, highlights. */\n accent: string;\n /** Title-card and letterbox background. */\n bg: string;\n bgSubtle: string;\n /** Caption card background (rgba string). */\n surface: string;\n onSurface: string;\n onSurfaceDim: string;\n fontFamily: string;\n captionFontPx: number;\n captionMinFontPx: number;\n captionMaxLines: number;\n captionPosition: 'bottom' | 'top' | 'off';\n radius: number;\n}\n\nconst DEFAULT_THEME: ResolvedTheme = {\n name: 'default',\n accent: '#5B8DEF',\n bg: '#12161f',\n bgSubtle: '#1a2029',\n surface: 'rgba(18, 22, 31, 0.92)',\n onSurface: '#ffffff',\n onSurfaceDim: 'rgba(255,255,255,0.72)',\n fontFamily: 'Inter',\n // Broadcast-subtitle scale: ~3.3% of a 1080p frame. At the old 26px the caption was the same\n // size as the app's upscaled body copy and read as part of the UI, not narration above it.\n captionFontPx: 36,\n captionMinFontPx: 28,\n captionMaxLines: 2,\n captionPosition: 'bottom',\n radius: 12,\n};\n\nexport function resolveTheme(spec: Spec): ResolvedTheme {\n return {\n ...DEFAULT_THEME,\n ...(spec.theme.accent ? { accent: spec.theme.accent } : {}),\n captionPosition: spec.theme.captions,\n };\n}\n\nlet fontsRegistered = false;\n\n/** Register bundled Inter faces so rendering is deterministic across machines. */\nexport function registerFonts(): void {\n if (fontsRegistered) return;\n fontsRegistered = true;\n const require = createRequire(import.meta.url);\n let pkgDir: string;\n try {\n pkgDir = dirname(require.resolve('@expo-google-fonts/inter/package.json'));\n } catch {\n throw new Error('Font package @expo-google-fonts/inter not found — run npm install');\n }\n const faces: [string, string][] = [\n ['400Regular/Inter_400Regular.ttf', 'Inter'],\n ['500Medium/Inter_500Medium.ttf', 'Inter Medium'],\n ['600SemiBold/Inter_600SemiBold.ttf', 'Inter SemiBold'],\n ['700Bold/Inter_700Bold.ttf', 'Inter Bold'],\n ];\n for (const [rel, family] of faces) {\n const p = join(pkgDir, rel);\n if (existsSync(p)) GlobalFonts.registerFromPath(p, family);\n }\n}\n","import type { Rect, Point, CameraState } from '../shared/geometry.js';\nimport type { BezierParams } from '../shared/easing.js';\nimport type { ResolvedTheme } from '../theme/index.js';\nimport type { ActionKind } from '../capture/events.js';\n\nexport interface OutputProfile {\n width: number;\n height: number;\n fps: number;\n /** Output-px margins content must respect; bottom includes the caption band. */\n safeArea: { top: number; right: number; bottom: number; left: number };\n zoomQuantums: number[];\n /** Minimum rendered size (output px) of a focus rect's smaller dimension. */\n minFocusPx: number;\n captionMaxWidth: number;\n /** Typography/chrome scale relative to the 1080-class design (min(w,h)/1080). Fixed-pixel\n * overlays at 4K rendered half-size and at 720p oversized (round-2 audit). */\n uiScale: number;\n /**\n * The stage: footage renders inside `content` (a matte with rounded corners, shadow, and an\n * optional browser-chrome bar above it) instead of edge-to-edge. ALL camera math — planner,\n * renderer, cursor projection, verification — runs in content space via `stageContent()`,\n * so plan and pixels can never disagree about where footage lives. Absent = full-frame.\n */\n stage?: {\n /** Output-px rect the footage is drawn into. */\n content: Rect;\n /** Height of the browser-chrome bar drawn directly above `content` (0 = none). */\n chromeH: number;\n radius: number;\n };\n}\n\n/** The rect footage renders into: the stage's content when present, else the full frame. */\nexport function stageContent(profile: OutputProfile): Rect {\n return profile.stage?.content ?? { x: 0, y: 0, w: profile.width, h: profile.height };\n}\n\n/** Compute a stage for the profile: matte margins + a chrome bar, with the content rect at\n * the CAPTURE VIEWPORT's aspect (not the output's) — this is what makes composing one bundle\n * to any output aspect geometrically sound: a 16:9 capture on a 9:16 canvas becomes a\n * correctly-proportioned card with generous mattes, never a distortion. */\nexport function withStage(profile: OutputProfile, chrome: boolean, viewportAspect?: number): OutputProfile {\n const { width, height } = profile;\n const va = viewportAspect ?? width / height;\n const ui = Math.min(width, height) / 1080;\n const marginY = Math.round(height * 0.055);\n const marginX = Math.round(width * 0.05);\n const chromeH = chrome ? Math.round(44 * ui) : 0;\n let contentH = height - 2 * marginY - chromeH;\n let contentW = Math.round(contentH * va);\n if (contentW > width - 2 * marginX) {\n contentW = width - 2 * marginX;\n contentH = Math.round(contentW / va);\n }\n const x = Math.round((width - contentW) / 2);\n const y = Math.round((height - contentH - chromeH) / 2) + chromeH;\n return {\n ...profile,\n stage: { content: { x, y, w: contentW, h: contentH }, chromeH, radius: Math.round(14 * ui) },\n };\n}\n\nexport const PROFILE_16x9: OutputProfile = {\n width: 1920,\n height: 1080,\n fps: 30,\n safeArea: { top: 54, right: 96, bottom: 160, left: 96 },\n zoomQuantums: [1.0, 1.15, 1.3, 1.5, 1.7, 2.0],\n minFocusPx: 110,\n captionMaxWidth: 1040,\n uiScale: 1,\n};\n\n/** Portrait: reserve more top/bottom for platform UI chrome; captions span most of the width. */\nexport const PROFILE_9x16: OutputProfile = {\n width: 1080,\n height: 1920,\n fps: 30,\n safeArea: { top: 230, right: 56, bottom: 320, left: 56 },\n zoomQuantums: [1.0, 1.15, 1.3, 1.5, 1.7, 2.0],\n minFocusPx: 96,\n captionMaxWidth: 980,\n uiScale: 1,\n};\n\nexport const PROFILE_1x1: OutputProfile = {\n width: 1080,\n height: 1080,\n fps: 30,\n safeArea: { top: 80, right: 72, bottom: 200, left: 72 },\n zoomQuantums: [1.0, 1.15, 1.3, 1.5, 1.7, 2.0],\n minFocusPx: 100,\n captionMaxWidth: 940,\n uiScale: 1,\n};\n\n/** Resolve the output profile for an aspect, overlaying the spec's resolution + fps. */\nexport function profileForAspect(\n aspect: '16:9' | '9:16' | '1:1',\n resolution: { w: number; h: number },\n fps: number,\n): OutputProfile {\n const base = aspect === '9:16' ? PROFILE_9x16 : aspect === '1:1' ? PROFILE_1x1 : PROFILE_16x9;\n const scaleX = resolution.w / base.width;\n const scaleY = resolution.h / base.height;\n return {\n ...base,\n width: resolution.w,\n height: resolution.h,\n fps,\n safeArea: {\n top: Math.round(base.safeArea.top * scaleY),\n bottom: Math.round(base.safeArea.bottom * scaleY),\n left: Math.round(base.safeArea.left * scaleX),\n right: Math.round(base.safeArea.right * scaleX),\n },\n captionMaxWidth: Math.round(base.captionMaxWidth * scaleX),\n uiScale: Math.min(resolution.w, resolution.h) / 1080,\n };\n}\n\nexport type TimeSegment =\n | { kind: 'source'; outStart: number; outEnd: number; srcStart: number; srcEnd: number }\n | { kind: 'freeze'; outStart: number; outEnd: number; srcAt: number }\n | { kind: 'card'; outStart: number; outEnd: number; cardId: string };\n\nexport interface CameraKeyframe {\n tOut: number;\n state: CameraState;\n /** Ease applied travelling from the previous keyframe to this one. */\n ease: BezierParams;\n}\n\nexport interface CursorSegment {\n tStart: number;\n tEnd: number;\n /** Arc-length-resampled polyline in viewport space. */\n path: Point[];\n clickAtEnd: boolean;\n}\n\nexport interface ClickRipple {\n tOut: number;\n /** Viewport space. */\n x: number;\n y: number;\n}\n\nexport interface CaptionOverlay {\n kind: 'caption';\n stepRef: string;\n ordinal: number;\n totalSteps: number;\n /** Whether to draw the numbered step badge (off for demo/release/social/factual styles). */\n showBadge: boolean;\n text: string;\n lines: string[];\n fontPx: number;\n /** Output-space card rect as rendered. */\n box: Rect;\n tStart: number;\n tEnd: number;\n shrunk: boolean;\n truncated: boolean;\n}\n\nexport interface TitleCardOverlay {\n kind: 'titleCard';\n cardId: string;\n title: string;\n subtitle?: string;\n tStart: number;\n tEnd: number;\n}\n\nexport interface DipTransition {\n kind: 'dip';\n tStart: number;\n tEnd: number;\n /** 'in' fades FROM the theme background into footage (post-title); 'out' fades footage\n * INTO the background (pre-end-card). Default 'in'. */\n direction?: 'in' | 'out';\n}\n\n/**\n * Act→react camera windows for a step that clicks one place and focuses another (\"click here,\n * LOOK there\"): the camera frames the action target around the beat, then hands off to the\n * focused payoff for the settled hold. Shared by the planner (to emit the handoff) and the\n * verifier (to assert each rect during ITS window) so plan and checks agree by construction.\n * Returns null when the step has no handoff (single rect, or too little hold to travel in).\n */\nexport function actReactWindows(step: StepMapEntry): {\n act: { rect: Rect; from: number; to: number };\n react: { rect: Rect; from: number; to: number };\n} | null {\n if (!step.focusRectVp || !step.targetRectVp) return null;\n if (step.focus === 'target' || step.focus === 'wide') return null;\n if (step.outEnd - step.outBeat < 1600) return null; // not enough hold to travel and settle\n return {\n act: { rect: step.targetRectVp, from: step.outBeat - 60, to: step.outBeat + 400 },\n react: { rect: step.focusRectVp, from: step.outBeat + 1100, to: step.outEnd },\n };\n}\n\n/** A persistent elapsed-time readout (bug-repro evidence). Rendered against the output clock. */\nexport interface ElapsedClockOverlay {\n kind: 'elapsedClock';\n tStart: number;\n tEnd: number;\n /** Output ms to subtract so the clock reads 0 at the first real action, not the title card. */\n zeroAtMs: number;\n}\n\n/** A brief scene-title label at each new scene (demo/before-after narrative structure). */\nexport interface ChapterLabelOverlay {\n kind: 'chapterLabel';\n title: string;\n ordinal: number;\n tStart: number;\n tEnd: number;\n}\n\n/** Closing card for a FAILED capture: the failure clip ends on what broke and why. */\nexport interface FailureCardOverlay {\n kind: 'failureCard';\n stepRef: string;\n message: string;\n tStart: number;\n tEnd: number;\n}\n\nexport type OverlayEntry =\n | CaptionOverlay\n | TitleCardOverlay\n | DipTransition\n | ElapsedClockOverlay\n | ChapterLabelOverlay\n | FailureCardOverlay;\n\nexport interface StepMapEntry {\n stepRef: string;\n sceneId: string;\n ordinal: number;\n kind: ActionKind;\n locator?: string;\n /** True for masked type steps — their visible effect is intentionally suppressed. */\n masked?: boolean;\n /** Viewport-space target rect at action time (bboxPre), when the step had a target. */\n targetRectVp?: Rect;\n /** Camera hint from the spec: 'target' | 'wide' | a locator string. */\n focus?: string;\n /** Shot-boundary control from the spec: 'cut' | 'continue'. */\n shot?: string;\n /** The action target VANISHED after settle (suggestion pick, menu item, dismissed dialog) —\n * effects like the spotlight must not linger over where it used to be. */\n targetGone?: boolean;\n /** Measured rect of a locator-valued focus hint at the settled moment — the payoff the\n * camera should frame instead of the action target (\"click here, look there\"). */\n focusRectVp?: Rect;\n outStart: number;\n /** Output-clock moment the action lands. */\n outBeat: number;\n outEnd: number;\n srcAction: number;\n srcSettled: number;\n}\n\nexport interface ComposeDiagnostics {\n overflows: { stepRef: string; text: string; action: 'shrunk' | 'truncated' }[];\n cameraFallbacks: string[];\n clockWarnings: string[];\n}\n\nexport interface ComposeManifest {\n schema: 'playhead/compose@1';\n profile: OutputProfile;\n viewport: { w: number; h: number };\n durationMs: number;\n totalFrames: number;\n segments: TimeSegment[];\n camera: CameraKeyframe[];\n cursor: CursorSegment[];\n ripples: ClickRipple[];\n overlays: OverlayEntry[];\n /** Cross-dissolve windows at scene boundaries: old footage (held at srcFrom) fades into new. */\n transitions?: { tStart: number; tEnd: number; srcFrom: number }[];\n steps: StepMapEntry[];\n theme: ResolvedTheme;\n diagnostics: ComposeDiagnostics;\n bundleHashes: { events: string; framesIndex: string };\n videoSha256?: string;\n /** Present when voice narration was muxed in. `clips` records where each spoken line landed\n * on the output clock, so verification can reason about voice-covered windows. */\n audio?: {\n narrated: boolean;\n provider: string;\n voice: string;\n lines: number;\n clips?: { stepRef: string; tStart: number; durMs: number }[];\n /** Set when the spec requested narration but TTS failed — the audio check FAILS on this,\n * so a degraded render can never quietly pass as publishable. */\n degraded?: string;\n };\n}\n","import type { OutputKind } from '../spec/schema.js';\n\nexport type CaptionStyle = 'instruction' | 'factual' | 'chapter';\n\n/** How a given output kind is composed — the same capture, a different treatment. */\nexport interface KindProfile {\n kind: OutputKind;\n /** Default pacing when the spec doesn't set one. */\n pacing: 'relaxed' | 'normal' | 'brisk';\n /** Caption phrasing: instructional (\"Click X\"), factual repro (\"Step 1 — click X\"), or narrative. */\n captionStyle: CaptionStyle;\n /** Prefix each caption with its number (\"1.\", \"2.\" …). */\n numberedCaptions: boolean;\n /** Draw a running elapsed-time clock (bug evidence). */\n elapsedClock: boolean;\n /** Insert a full-frame chapter card at each new scene (demo narrative structure). */\n chapterCards: boolean;\n /** Hold on the final state this long (ms) — bug-repro dwells on the defect. */\n outroMs: number;\n /** Typed input is shown as evidence even in fields that look sensitive (repro needs the values). */\n showTypedInput: boolean;\n /** Composition-driven camera emphasis + click spotlights. Off for bug-repro, which must stay\n * a literal record of the screen. */\n cameraEmphasis: boolean;\n /** Render footage on a stage (matte + rounded card + browser chrome) instead of edge-to-edge. */\n stage: boolean;\n}\n\nconst BASE: Omit<KindProfile, 'kind'> = {\n pacing: 'normal',\n captionStyle: 'instruction',\n numberedCaptions: true,\n elapsedClock: false,\n chapterCards: false,\n outroMs: 1600,\n showTypedInput: true,\n cameraEmphasis: true,\n stage: true,\n};\n\nconst PROFILES: Record<OutputKind, KindProfile> = {\n walkthrough: { kind: 'walkthrough', ...BASE },\n demo: {\n kind: 'demo',\n ...BASE,\n pacing: 'relaxed',\n captionStyle: 'chapter',\n numberedCaptions: false,\n chapterCards: true,\n outroMs: 2200,\n },\n 'bug-repro': {\n kind: 'bug-repro',\n ...BASE,\n pacing: 'normal',\n captionStyle: 'factual',\n numberedCaptions: true,\n elapsedClock: true,\n outroMs: 3000,\n // A repro is EVIDENCE: no directorial zoom, no spotlights, no matte — the literal screen.\n cameraEmphasis: false,\n stage: false,\n },\n 'before-after': { kind: 'before-after', ...BASE, pacing: 'normal', chapterCards: true, numberedCaptions: false },\n release: { kind: 'release', ...BASE, pacing: 'brisk', numberedCaptions: false, outroMs: 1400 },\n social: { kind: 'social', ...BASE, pacing: 'brisk', numberedCaptions: false, outroMs: 1400 },\n};\n\nexport function kindProfile(kind: OutputKind): KindProfile {\n return PROFILES[kind] ?? PROFILES.walkthrough;\n}\n","import type { Rect, Point } from '../shared/geometry.js';\n\n/** All event/frame times are milliseconds relative to capture start, on one normalized clock. */\n\nexport interface TargetInfo {\n role: string | null;\n accessibleName: string | null;\n /** Viewport-relative (client) CSS px — exactly the space the captured frames show. */\n bbox: Rect;\n /** Window scroll offsets at measure time, CSS px. */\n scroll: Point;\n}\n\nexport interface CursorWaypoint {\n x: number;\n y: number;\n t: number;\n}\n\nexport type ActionKind =\n | 'goto'\n | 'click'\n | 'rightclick'\n | 'upload'\n | 'drag'\n | 'dblclick'\n | 'hover'\n | 'type'\n | 'press'\n | 'select'\n | 'scroll'\n | 'expect'\n | 'wait';\n\nexport interface ActionEvent {\n type: 'action';\n kind: ActionKind;\n sceneId: string;\n stepIndex: number;\n /** Global 1-based step number across the whole spec. */\n ordinal: number;\n locator?: string;\n targetPre?: TargetInfo | null;\n targetPost?: TargetInfo | null;\n cursorPath: CursorWaypoint[];\n /** Redacted to bullets when masked — the real string never enters any artifact. */\n typedText?: string;\n masked?: boolean;\n /** Caption override from the spec, carried through for the compositor. */\n caption?: string;\n /** Spoken-line override from the spec (TTS narration), carried as a record — the live spec\n * wins at compose time. */\n narration?: string;\n /** Camera-shot boundary control from the spec ('cut' | 'continue'). */\n shot?: string;\n /** Camera hint from the spec: 'target' | 'wide' | a locator string. */\n focus?: string;\n /** When `focus` names a locator, its measured geometry at the settled moment — the payoff\n * rect the camera should frame (\"click here, look there\"). */\n focusTarget?: TargetInfo | null;\n tStart: number;\n /** Moment the action lands (mouse-down, first keystroke, key chord). */\n tAction: number;\n /** Action fully delivered (mouse-up, last keystroke). */\n tActionEnd: number;\n /** UI settled after the action (network idle + layout stable). */\n tSettled: number;\n}\n\nexport interface NavigationEvent {\n type: 'navigation';\n url: string;\n t: number;\n}\n\nexport type CaptureEvent = ActionEvent | NavigationEvent;\n\nexport interface EventLogMeta {\n viewport: { w: number; h: number };\n dpr: number;\n /** Actual pixel dimensions of captured frames (source of truth for frame-space scale). */\n frameW: number;\n frameH: number;\n clockOffsetMs: number;\n startedAtIso: string;\n durationMs: number;\n appUrl: string;\n}\n\nexport interface EventLog {\n schema: 'playhead/events@1';\n meta: EventLogMeta;\n events: CaptureEvent[];\n}\n\nexport function actionEvents(log: EventLog): ActionEvent[] {\n return log.events.filter((e): e is ActionEvent => e.type === 'action');\n}\n\nexport function navigationEvents(log: EventLog): NavigationEvent[] {\n return log.events.filter((e): e is NavigationEvent => e.type === 'navigation');\n}\n","/** Narration placement constants, shared by the timeline (dwell fitting) and the muxer. */\n\n/** A step's spoken line starts this long after the step (and its caption) begin. */\nexport const AUDIO_LEAD_MS = 150;\n/** Silence kept after a spoken line finishes before the step is allowed to end. */\nexport const AUDIO_TAIL_MS = 450;\n","import type { EventLog, ActionEvent, ActionKind } from '../../capture/events.js';\nimport { actionEvents } from '../../capture/events.js';\nimport type { TimeSegment, StepMapEntry } from '../types.js';\nimport { AUDIO_LEAD_MS, AUDIO_TAIL_MS } from '../../audio/timing.js';\n\nexport interface PacingConfig {\n factor: number;\n titleCardMs: number;\n introMaxMs: number;\n outroMs: number;\n idleGapMaxMs: number;\n idleGapOutMs: number;\n minStepMs: number;\n maxTypeOutMs: number;\n holds: Record<ActionKind, number>;\n}\n\nexport function pacingConfig(mode: 'relaxed' | 'normal' | 'brisk', kind?: { outroMs: number }): PacingConfig {\n const factor = mode === 'relaxed' ? 1.25 : mode === 'brisk' ? 0.8 : 1;\n return {\n factor,\n titleCardMs: 2200,\n introMaxMs: 1200,\n outroMs: kind?.outroMs ?? 1600,\n idleGapMaxMs: 1500,\n idleGapOutMs: 400,\n minStepMs: 1800 * factor,\n maxTypeOutMs: 4500,\n holds: {\n goto: 1200 * factor,\n click: 600 * factor,\n dblclick: 600 * factor,\n hover: 450 * factor,\n type: 450 * factor,\n press: 450 * factor,\n select: 600 * factor,\n rightclick: 700 * factor,\n upload: 800 * factor,\n drag: 700 * factor,\n scroll: 350 * factor,\n expect: 800 * factor,\n wait: 150,\n },\n };\n}\n\nexport interface TimelinePlan {\n segments: TimeSegment[];\n steps: StepMapEntry[];\n durationMs: number;\n}\n\n/**\n * Build the output timeline: title card, per-step source spans with compose-time\n * pacing (idle-gap trimming, post-action freezes, min-step extension), and an\n * outro hold on the final state.\n */\nexport function buildTimeline(log: EventLog, cfg: PacingConfig, audioMs?: Map<string, number>): TimelinePlan {\n const events = actionEvents(log);\n const segments: TimeSegment[] = [];\n const steps: StepMapEntry[] = [];\n\n segments.push({ kind: 'card', outStart: 0, outEnd: cfg.titleCardMs, cardId: 'title' });\n let out = cfg.titleCardMs;\n let src = events.length > 0 ? Math.max(0, events[0]!.tStart - cfg.introMaxMs) : 0;\n\n for (const e of events) {\n // Gap between the previous settle and this step's start.\n const gap = e.tStart - src;\n if (gap > 1) {\n const outDur = gap > cfg.idleGapMaxMs ? cfg.idleGapOutMs : gap;\n segments.push({ kind: 'source', outStart: out, outEnd: out + outDur, srcStart: src, srcEnd: e.tStart });\n out += outDur;\n }\n const stepOutStart = out;\n\n // Action span. Typing is retimed in THREE pieces instead of a uniform speed-up: the first\n // keystrokes and the last ones play at natural rhythm (that's where the eye reads cadence)\n // and only the middle fast-forwards — a long field reads as \"typed, skipped ahead, landed\"\n // rather than a robotic constant-rate blur (round-2 audit craft note).\n const srcEnd = Math.max(e.tSettled, e.tActionEnd, e.tStart + 1);\n const spanSrc = srcEnd - e.tStart;\n let spanOut = spanSrc;\n let outBeat: number;\n if (e.kind === 'type' && spanSrc > cfg.maxTypeOutMs) {\n const HEAD_MS = 1200; // natural-rate opening keystrokes\n const TAIL_MS = 700; // natural-rate landing keystrokes\n const headSrc = Math.min(HEAD_MS, spanSrc * 0.4);\n const tailSrc = Math.min(TAIL_MS, spanSrc * 0.25);\n const midSrc = spanSrc - headSrc - tailSrc;\n const midOut = Math.max(250, cfg.maxTypeOutMs - headSrc - tailSrc);\n segments.push({ kind: 'source', outStart: out, outEnd: out + headSrc, srcStart: e.tStart, srcEnd: e.tStart + headSrc });\n segments.push({\n kind: 'source',\n outStart: out + headSrc,\n outEnd: out + headSrc + midOut,\n srcStart: e.tStart + headSrc,\n srcEnd: e.tStart + headSrc + midSrc,\n });\n segments.push({\n kind: 'source',\n outStart: out + headSrc + midOut,\n outEnd: out + headSrc + midOut + tailSrc,\n srcStart: srcEnd - tailSrc,\n srcEnd,\n });\n spanOut = headSrc + midOut + tailSrc;\n // The beat (first keystroke) lands inside the natural-rate head.\n outBeat = out + Math.min(e.tAction - e.tStart, headSrc);\n out += spanOut;\n } else {\n segments.push({ kind: 'source', outStart: out, outEnd: out + spanOut, srcStart: e.tStart, srcEnd });\n outBeat = out + (e.tAction - e.tStart) * (spanOut / spanSrc);\n out += spanOut;\n }\n\n // Post-action freeze: fixed hold, extended to satisfy the minimum step duration.\n let hold = cfg.holds[e.kind];\n if (out + hold - stepOutStart < cfg.minStepMs) hold = cfg.minStepMs - (out - stepOutStart);\n // Narration-driven pacing: grow the hold so the step lasts long enough for its\n // spoken line (lead-in + speech + tail) to finish before the step ends.\n const aud = audioMs?.get(`${e.sceneId}/${e.stepIndex}`);\n if (aud && aud > 0) {\n const need = AUDIO_LEAD_MS + aud + AUDIO_TAIL_MS;\n const have = out - stepOutStart + hold;\n if (have < need) hold += need - have;\n }\n // Act→react pacing: a step whose focus hands the camera off to a payoff element needs\n // enough post-beat hold for the travel plus a settled look at the destination.\n if (e.focusTarget && e.focus && e.focus !== 'target' && e.focus !== 'wide') {\n const needAfterBeat = 2100;\n const haveAfterBeat = out + hold - outBeat;\n if (haveAfterBeat < needAfterBeat) hold += needAfterBeat - haveAfterBeat;\n }\n if (hold > 0.5) {\n segments.push({ kind: 'freeze', outStart: out, outEnd: out + hold, srcAt: srcEnd });\n out += hold;\n }\n\n steps.push({\n stepRef: `${e.sceneId}/${e.stepIndex}`,\n sceneId: e.sceneId,\n ordinal: e.ordinal,\n kind: e.kind,\n ...(e.locator ? { locator: e.locator } : {}),\n ...(e.masked ? { masked: true } : {}),\n ...(e.targetPre ? { targetRectVp: e.targetPre.bbox } : {}),\n ...(e.focus ? { focus: e.focus } : {}),\n ...(e.shot ? { shot: e.shot } : {}),\n ...(e.focusTarget ? { focusRectVp: e.focusTarget.bbox } : {}),\n ...(e.targetPre && !e.targetPost ? { targetGone: true } : {}),\n outStart: stepOutStart,\n outBeat,\n outEnd: out,\n srcAction: e.tAction,\n srcSettled: srcEnd,\n });\n src = srcEnd;\n }\n\n // Outro: hold the final state.\n const lastSrc = Math.max(src, log.meta.durationMs - 1);\n segments.push({ kind: 'freeze', outStart: out, outEnd: out + cfg.outroMs, srcAt: lastSrc });\n out += cfg.outroMs;\n\n return { segments, steps, durationMs: out };\n}\n\n/** Map an output time to a source time (null on card segments). */\nexport function sampleSource(segments: TimeSegment[], tOut: number): { srcAt: number | null; segment: TimeSegment } {\n const seg = segmentAt(segments, tOut);\n switch (seg.kind) {\n case 'card':\n return { srcAt: null, segment: seg };\n case 'freeze':\n return { srcAt: seg.srcAt, segment: seg };\n case 'source': {\n const u = (tOut - seg.outStart) / Math.max(1e-6, seg.outEnd - seg.outStart);\n return { srcAt: seg.srcStart + u * (seg.srcEnd - seg.srcStart), segment: seg };\n }\n }\n}\n\n/** Inverse of sampleSource: the FIRST output time at which source time tSrc is on screen —\n * through a `source` segment (linear map) or a `freeze` holding a frame at/after tSrc.\n * Null when the source moment was trimmed out entirely. */\nexport function outTimeForSrc(segments: TimeSegment[], tSrc: number): number | null {\n for (const seg of segments) {\n if (seg.kind === 'source' && tSrc >= seg.srcStart && tSrc <= seg.srcEnd) {\n const u = (tSrc - seg.srcStart) / Math.max(1e-6, seg.srcEnd - seg.srcStart);\n return seg.outStart + u * (seg.outEnd - seg.outStart);\n }\n if (seg.kind === 'freeze' && Math.abs(seg.srcAt - tSrc) < 400) {\n return seg.outStart + (seg.outEnd - seg.outStart) / 2;\n }\n }\n return null;\n}\n\nexport function segmentAt(segments: TimeSegment[], tOut: number): TimeSegment {\n let lo = 0;\n let hi = segments.length - 1;\n if (tOut <= segments[0]!.outStart) return segments[0]!;\n if (tOut >= segments[hi]!.outEnd) return segments[hi]!;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (segments[mid]!.outEnd <= tOut) lo = mid + 1;\n else hi = mid;\n }\n return segments[lo]!;\n}\n\n/** Events keyed by stepRef, for callers pairing steps back to their events. */\nexport function eventByStepRef(log: EventLog): Map<string, ActionEvent> {\n const map = new Map<string, ActionEvent>();\n for (const e of actionEvents(log)) map.set(`${e.sceneId}/${e.stepIndex}`, e);\n return map;\n}\n","import type { CameraKeyframe } from '../types.js';\nimport type { CameraState } from '../../shared/geometry.js';\nimport { cubicBezier } from '../../shared/easing.js';\n\n/**\n * Sample the camera path at an output time.\n *\n * Interpolation is cubic Hermite with Catmull-Rom-style tangents, which makes the camera\n * VELOCITY-CONTINUOUS through chains of consecutive moves — the round-2 audit's \"camera stops\n * dead at every keyframe\" (pan-stop-zoom-stop on every via-wide maneuver). Two invariants:\n *\n * 1. HOLDS STAY PIXEL-STILL. A hold is a pair of identical keyframes; any tangent flowing\n * across it would drift the camera during the very windows the framing guarantee samples.\n * Tangents are therefore clamped to zero at every hold boundary — a move eases smoothly to\n * a full rest exactly at its destination, and chains of moves flow through each other.\n * 2. Zoom interpolates in LOG space (linear zoom reads as acceleration).\n *\n * With zero tangents at both ends (an isolated move between holds) Hermite degenerates to a\n * smoothstep, i.e. the previous ease-in-out behavior — so single moves look unchanged.\n * The planner's constraint pass samples THIS function, so any overshoot from the tangents is\n * caught by the same framing check that governs everything else.\n */\nexport function sampleCamera(keyframes: CameraKeyframe[], tOut: number): CameraState {\n if (keyframes.length === 0) return { cx: 0, cy: 0, zoom: 1 };\n if (tOut <= keyframes[0]!.tOut) return { ...keyframes[0]!.state };\n const last = keyframes[keyframes.length - 1]!;\n if (tOut >= last.tOut) return { ...last.state };\n\n let lo = 0;\n let hi = keyframes.length - 1;\n while (lo < hi - 1) {\n const mid = (lo + hi) >> 1;\n if (keyframes[mid]!.tOut <= tOut) lo = mid;\n else hi = mid;\n }\n const a = keyframes[lo]!;\n const b = keyframes[hi]!;\n const dt = Math.max(1e-6, b.tOut - a.tOut);\n const u = (tOut - a.tOut) / dt;\n\n // A hold segment: nothing to interpolate.\n if (sameState(a.state, b.state)) return { ...a.state };\n\n // Component-wise values with zoom in log space.\n const va = [a.state.cx, a.state.cy, Math.log(a.state.zoom)];\n const vb = [b.state.cx, b.state.cy, Math.log(b.state.zoom)];\n\n // Tangents (per ms) at each end. Zero when the adjacent segment is a hold or the endpoint —\n // this is what keeps holds pixel-still while chained moves stay velocity-continuous.\n const TENSION = 0.5; // damps Catmull-Rom overshoot\n const ma = tangentAt(keyframes, lo, TENSION);\n const mb = tangentAt(keyframes, hi, TENSION);\n\n // If both tangents are zero, fall back to the keyframe's authored ease (identical to the\n // previous behavior for isolated moves).\n const isolated = ma.every((m) => m === 0) && mb.every((m) => m === 0);\n if (isolated) {\n const e = cubicBezier(b.ease, u);\n return {\n cx: va[0]! + (vb[0]! - va[0]!) * e,\n cy: va[1]! + (vb[1]! - va[1]!) * e,\n zoom: Math.exp(va[2]! + (vb[2]! - va[2]!) * e),\n };\n }\n\n // Cubic Hermite basis.\n const u2 = u * u;\n const u3 = u2 * u;\n const h00 = 2 * u3 - 3 * u2 + 1;\n const h10 = u3 - 2 * u2 + u;\n const h01 = -2 * u3 + 3 * u2;\n const h11 = u3 - u2;\n const out = [0, 0, 0];\n for (let c = 0; c < 3; c++) {\n out[c] = h00 * va[c]! + h10 * dt * ma[c]! + h01 * vb[c]! + h11 * dt * mb[c]!;\n }\n return { cx: out[0]!, cy: out[1]!, zoom: Math.exp(out[2]!) };\n}\n\n/** Catmull-Rom tangent (per ms) at keyframe i, zeroed at endpoints and hold boundaries. */\nfunction tangentAt(keyframes: CameraKeyframe[], i: number, tension: number): number[] {\n const cur = keyframes[i]!;\n const prev = i > 0 ? keyframes[i - 1]! : null;\n const next = i < keyframes.length - 1 ? keyframes[i + 1]! : null;\n // Endpoint, or adjacent to a hold on either side → full stop here.\n if (!prev || !next) return [0, 0, 0];\n if (sameState(prev.state, cur.state) || sameState(cur.state, next.state)) return [0, 0, 0];\n const dt = Math.max(1e-6, next.tOut - prev.tOut);\n const vp = [prev.state.cx, prev.state.cy, Math.log(prev.state.zoom)];\n const vn = [next.state.cx, next.state.cy, Math.log(next.state.zoom)];\n return [0, 1, 2].map((c) => (tension * (vn[c]! - vp[c]!)) / dt);\n}\n\nfunction sameState(a: CameraState, b: CameraState): boolean {\n return Math.abs(a.cx - b.cx) < 0.5 && Math.abs(a.cy - b.cy) < 0.5 && Math.abs(a.zoom - b.zoom) < 1e-3;\n}\n","import type { CameraKeyframe, OutputProfile, StepMapEntry } from '../types.js';\nimport { stageContent, actReactWindows } from '../types.js';\nimport type { EventLog } from '../../capture/events.js';\nimport { navigationEvents } from '../../capture/events.js';\nimport {\n type CameraPlane,\n type CameraState,\n type Rect,\n clamp,\n clampCamera,\n minZoom,\n padRect,\n projectRect,\n rectCenter,\n rectContains,\n rectUnion,\n} from '../../shared/geometry.js';\nimport { EASE_PAN, EASE_ZOOM } from '../../shared/easing.js';\nimport { sampleCamera } from './interpolate.js';\n\nconst FOCUS_PAD_VP = 24;\nconst SHOT_MAX_GAP_MS = 4000;\nconst PAN_DEADBAND_VP = 48;\nconst TRAVEL_MIN_MS = 500;\nconst TRAVEL_MAX_MS = 900;\nconst ARRIVE_LEAD_MS = 80;\n/** Target rendered height (output px) the zoom aims to give the smallest target — comfortably\n * above the verifier's 28px legibility floor so quantization rounding stays safe. */\nconst LEGIBLE_TARGET_PX = 34;\n\ninterface Shot {\n stepRefs: string[];\n sceneId: string;\n focus: Rect;\n /** Smallest unpadded target dimension across the shot's members (viewport px) — this, not the\n * union size, is what the legibility zoom must satisfy so every member stays readable. */\n minTargetDim: number;\n wide: boolean;\n outStart: number;\n firstBeat: number;\n outEnd: number;\n zoomIndex: number;\n state?: CameraState;\n}\n\nexport interface CameraPlanResult {\n keyframes: CameraKeyframe[];\n fallbacks: string[];\n}\n\n/**\n * Plan the camera path from measured step geometry. Craft rules: quantized zoom levels,\n * legibility-driven zoom selection, caption-safe-area bias, pull-backs on navigation and\n * long pans, and an analytic constraint pass that guarantees each target stays framed.\n */\nexport function planCamera(\n steps: StepMapEntry[],\n log: EventLog,\n profile: OutputProfile,\n durationMs: number,\n opts?: { emphasis?: boolean },\n): CameraPlanResult {\n // The camera projects into the STAGE's content rect (or the full frame without a stage):\n // one shared space for planner, renderer, cursor, and verification.\n const content = stageContent(profile);\n const plane: CameraPlane = {\n vpW: log.meta.viewport.w,\n vpH: log.meta.viewport.h,\n outW: content.w,\n outH: content.h,\n };\n const emphasis = opts?.emphasis ?? true;\n const fallbacks: string[] = [];\n\n // Sharpness-bounded zoom quantums: the frame buffer only has frameW real pixels across.\n // Upscales beyond ~1.28x read as soft, so cap quantums there. (The stage helps here: content\n // renders smaller than the frame, so the same capture supports deeper sharp zooms.)\n const sharpZoom = log.meta.frameW > 0 ? log.meta.frameW / content.w : 1.3;\n const zMaxAllowed = Math.max(minZoom(plane), sharpZoom * 1.28);\n const quantums = profile.zoomQuantums.filter((q) => q <= zMaxAllowed + 1e-6);\n if (quantums.length === 0) quantums.push(1);\n\n const navTimes = navigationEvents(log).map((n) => n.t);\n const shots = groupShots(steps, navTimes, plane, durationMs);\n\n // Budget scales with the problem: every shot could need every quantum stepped down and then\n // a wide fallback. The old fixed 4 attempts could exhaust on busy specs and RE-EMIT WITHOUT\n // A FINAL CHECK — shipping a silently violating camera path (round-2 audit).\n const maxAttempts = Math.max(8, shots.length * (quantums.length + 1));\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n for (const shot of shots) shot.state = shotState(shot, quantums, plane, profile, emphasis);\n const keyframes = emitKeyframes(shots, plane, durationMs);\n const violation = checkConstraints(keyframes, steps, plane, profile);\n if (!violation) return { keyframes, fallbacks };\n\n // An act→react step owns TWO shots with the same stepRef — pick the one whose time window\n // contains the violation, falling back to stepRef membership.\n const shot =\n shots.find(\n (s) => s.stepRefs.includes(violation.stepRef) && violation.tOut >= s.outStart && violation.tOut <= s.outEnd,\n ) ?? shots.find((s) => s.stepRefs.includes(violation.stepRef));\n if (!shot || shot.zoomIndex === 0 || shot.wide) {\n fallbacks.push(`${violation.stepRef}: unresolvable framing violation — falling back to wide`);\n if (shot) shot.wide = true;\n else break;\n } else {\n shot.zoomIndex -= 1;\n fallbacks.push(`${violation.stepRef}: reduced shot zoom to satisfy framing constraints`);\n }\n }\n // Exhausted: force EVERYTHING wide (guaranteed constraint-free — wide never crops) and say so.\n for (const shot of shots) shot.wide = true;\n for (const shot of shots) shot.state = shotState(shot, quantums, plane, profile, emphasis);\n fallbacks.push('camera planner exhausted its attempt budget — all shots forced wide (check for conflicting focus hints)');\n return { keyframes: emitKeyframes(shots, plane, durationMs), fallbacks };\n}\n\nfunction groupShots(steps: StepMapEntry[], navTimes: number[], plane: CameraPlane, durationMs: number): Shot[] {\n const shots: Shot[] = [];\n let current: Shot | null = null;\n\n const navBetween = (a: number, b: number) => navTimes.some((t) => t > a && t <= b);\n\n for (const step of steps) {\n // Act→react: the step clicks one place and focuses another, with enough hold to travel.\n // Emit TWO shots — frame the action target through the beat, then hand the camera off to\n // the payoff for the settled hold (\"click here, look there\" inside one step).\n const handoff = actReactWindows(step);\n if (handoff) {\n const actFocus = padRect(handoff.act.rect, FOCUS_PAD_VP);\n const reactFocus = padRect(handoff.react.rect, FOCUS_PAD_VP);\n shots.push({\n stepRefs: [step.stepRef],\n sceneId: step.sceneId,\n focus: actFocus,\n minTargetDim: Math.min(handoff.act.rect.w, handoff.act.rect.h),\n wide: false,\n outStart: step.outStart,\n firstBeat: step.outBeat,\n outEnd: handoff.act.to,\n zoomIndex: Number.MAX_SAFE_INTEGER,\n });\n shots.push({\n stepRefs: [step.stepRef],\n sceneId: step.sceneId,\n focus: reactFocus,\n minTargetDim: Math.min(handoff.react.rect.w, handoff.react.rect.h),\n wide: false,\n outStart: handoff.act.to,\n firstBeat: handoff.react.from, // arrive by the react window's start\n outEnd: step.outEnd,\n zoomIndex: Number.MAX_SAFE_INTEGER,\n });\n current = null; // never merge across a handoff\n continue;\n }\n\n let rect = step.kind === 'goto' ? undefined : step.targetRectVp;\n // goto and scroll are wide by nature: goto changes everything; a scroll's meaning is the\n // motion, not a specific small element (so scroll targets are exempt from the legibility\n // floor elsewhere — they need only be in frame).\n let wide = !rect || step.kind === 'goto' || step.kind === 'scroll';\n // The spec's focus hint is AUTHORITY, not a suggestion: 'wide' forces a wide shot; 'target'\n // forces this step's own framed shot (never merged away); a locator-valued focus swaps the\n // framed rect for the measured payoff element — this is what lets a goto or a sidebar click\n // frame the thing that CHANGED rather than the thing that was clicked.\n if (step.focus === 'wide') {\n wide = true;\n } else if (step.focusRectVp) {\n rect = step.focusRectVp;\n wide = false;\n } else if (step.focus === 'target' && rect) {\n wide = false;\n }\n // Spec shot control: 'cut' forces this step into a fresh shot; 'continue' merges into the\n // previous shot even when the heuristic would split — the author's cut list wins.\n if (step.shot === 'cut') current = null;\n const forceContinue = step.shot === 'continue';\n if (forceContinue && current && rect && current.sceneId === step.sceneId) {\n current.stepRefs.push(step.stepRef);\n current.focus = rectUnion(current.focus, padRect(rect, FOCUS_PAD_VP));\n current.minTargetDim = Math.min(current.minTargetDim, Math.min(rect.w, rect.h));\n current.outEnd = step.outEnd;\n continue;\n }\n const noMerge = step.focus === 'target' || step.focusRectVp !== undefined;\n // A shot never spans scenes: hash-route changes don't fire a navigation event, so scene\n // identity — not navBetween alone — is what keeps a tour's views from merging into one\n // un-zoomable mega-shot.\n if (current && !noMerge && current.sceneId === step.sceneId && !current.wide && !wide && rect) {\n const prevSrc = current.stepRefs.length > 0 ? steps.find((s) => s.stepRef === current!.stepRefs[current!.stepRefs.length - 1])!.srcSettled : 0;\n const union = rectUnion(current.focus, padRect(rect, FOCUS_PAD_VP));\n // A merge must keep the SMALLEST member legible: if the union can only be shown at a zoom\n // below what the smallest target needs, merging would dilute it (a small pipeline card\n // pulled into a wide modal shot renders too small) — so keep them as separate shots.\n const baseScale = plane.outW / plane.vpW;\n const mergedMinDim = Math.min(current.minTargetDim, Math.min(rect.w, rect.h));\n const zNeeded = Math.min(LEGIBLE_TARGET_PX / (mergedMinDim * baseScale), 1.6);\n const zFitUnion = fitZoom(union, plane) * 0.92;\n const fitsTogether = fitZoom(union, plane) >= 1.2 && zFitUnion >= zNeeded - 0.02;\n const closeInTime = step.outStart - current.outEnd < SHOT_MAX_GAP_MS;\n if (fitsTogether && closeInTime && !navBetween(prevSrc, step.srcAction)) {\n current.stepRefs.push(step.stepRef);\n current.focus = union;\n current.minTargetDim = Math.min(current.minTargetDim, Math.min(rect.w, rect.h));\n current.outEnd = step.outEnd;\n continue;\n }\n }\n // A framed NAVIGATION shot must not dive into the payoff's coordinates while the old page\n // (or a white flash) is still on screen — key its arrival to when the settled content is\n // actually visible, not the click (round-2 audit).\n const arriveBeat =\n step.kind === 'goto' && rect\n ? Math.min(step.outEnd - 400, step.outBeat + Math.max(200, step.srcSettled - step.srcAction) + 150)\n : step.outBeat;\n current = {\n stepRefs: [step.stepRef],\n sceneId: step.sceneId,\n focus: rect ? padRect(rect, FOCUS_PAD_VP) : { x: 0, y: 0, w: plane.vpW, h: plane.vpH },\n minTargetDim: rect ? Math.min(rect.w, rect.h) : Math.min(plane.vpW, plane.vpH),\n wide,\n outStart: step.outStart,\n firstBeat: arriveBeat,\n outEnd: step.outEnd,\n zoomIndex: Number.MAX_SAFE_INTEGER, // resolved in shotState\n };\n shots.push(current);\n }\n if (shots.length > 0) shots[shots.length - 1]!.outEnd = Math.min(shots[shots.length - 1]!.outEnd, durationMs);\n return shots;\n}\n\n/** Max zoom at which a viewport rect still fits in the visible window with margin. */\nfunction fitZoom(rect: Rect, plane: CameraPlane): number {\n const zw = plane.vpW / rect.w;\n const zh = (plane.vpW * plane.outH) / plane.outW / rect.h;\n return Math.min(zw, zh);\n}\n\n/** Fraction of the fit-zoom a focus rect should occupy when the camera emphasises it: at 0.5\n * the subject fills roughly half the frame's limiting dimension — close enough to direct the\n * eye, wide enough to keep context. This, not legibility, is what makes shots feel FRAMED. */\nconst OCCUPANCY = 0.5;\n\nfunction shotState(\n shot: Shot,\n quantums: number[],\n plane: CameraPlane,\n profile: OutputProfile,\n emphasis: boolean,\n): CameraState {\n const zMin = minZoom(plane);\n if (shot.wide) {\n return clampCamera({ cx: plane.vpW / 2, cy: rectCenter(shot.focus).y, zoom: zMin }, plane);\n }\n const baseScale = plane.outW / plane.vpW;\n // Legibility is driven by the SMALLEST member target (so a small element merged into a large\n // shot still gets enough zoom), while fit is driven by the whole union (so nothing is cropped).\n const minDim = Math.max(6, shot.minTargetDim);\n const zLegibility = LEGIBLE_TARGET_PX / (minDim * baseScale);\n const zFit = fitZoom(shot.focus, plane) * 0.92;\n\n // Composition: zoom is a DIRECTORIAL choice, not just a legibility floor. Without this, any\n // target above ~23 viewport px resolves to zoom 1.0 and the whole video plays wide and flat.\n const zComposition = emphasis ? OCCUPANCY * fitZoom(shot.focus, plane) : 0;\n const zWant = Math.max(zLegibility, zComposition);\n\n // Choose the smallest quantum ≥ the wanted zoom (round UP — an under-framed subject is the\n // defect we most want to avoid), but never past what fits without cropping.\n const maxFit = Math.min(zFit, quantums[quantums.length - 1]!);\n let zoomIndex = 0;\n let reachedWant = false;\n for (let i = 0; i < quantums.length; i++) {\n if (quantums[i]! > maxFit + 1e-6) break;\n zoomIndex = i; // largest quantum that still fits, as a fallback\n if (!reachedWant && quantums[i]! >= zWant - 1e-6) {\n zoomIndex = i;\n reachedWant = true;\n break;\n }\n }\n shot.zoomIndex = Math.min(shot.zoomIndex, zoomIndex);\n const zoom = Math.max(quantums[shot.zoomIndex]!, zMin);\n\n const center = rectCenter(shot.focus);\n let state = clampCamera({ cx: center.x, cy: center.y, zoom }, plane);\n\n // Bias the focus rect into the content safe area (out of the caption band).\n for (let i = 0; i < 3; i++) {\n const proj = projectRect(shot.focus, state, plane);\n const safe = contentArea(profile);\n let dyOut = 0;\n if (proj.y + proj.h > safe.y + safe.h) dyOut = proj.y + proj.h - (safe.y + safe.h);\n else if (proj.y < safe.y) dyOut = proj.y - safe.y;\n let dxOut = 0;\n if (proj.x + proj.w > safe.x + safe.w) dxOut = proj.x + proj.w - (safe.x + safe.w);\n else if (proj.x < safe.x) dxOut = proj.x - safe.x;\n if (Math.abs(dxOut) < 1 && Math.abs(dyOut) < 1) break;\n const visW = plane.vpW / state.zoom;\n const scale = visW / plane.outW;\n state = clampCamera({ cx: state.cx + dxOut * scale, cy: state.cy + dyOut * scale, zoom: state.zoom }, plane);\n }\n return state;\n}\n\n/** The safe area, expressed in PLANE space (stage content coords when a stage is set): frame\n * margins translated into the content rect, with a small floor so it never collapses. */\nexport function contentArea(profile: OutputProfile): Rect {\n const s = stageContent(profile);\n const left = Math.max(profile.safeArea.left - s.x, 8);\n const top = Math.max(profile.safeArea.top - s.y, 8);\n const right = Math.min(s.w - 8, profile.width - profile.safeArea.right - s.x);\n const bottom = Math.min(s.h - 8, profile.height - profile.safeArea.bottom - s.y);\n return { x: left, y: top, w: Math.max(16, right - left), h: Math.max(16, bottom - top) };\n}\n\nfunction emitKeyframes(shots: Shot[], plane: CameraPlane, durationMs: number): CameraKeyframe[] {\n const kfs: CameraKeyframe[] = [];\n const wideState = clampCamera({ cx: plane.vpW / 2, cy: plane.vpH / 2, zoom: minZoom(plane) }, plane);\n let prevState = wideState;\n let prevEnd = 0;\n kfs.push({ tOut: 0, state: wideState, ease: EASE_ZOOM });\n\n for (const shot of shots) {\n const target = shot.state!;\n const panDist = Math.hypot(target.cx - prevState.cx, target.cy - prevState.cy);\n const zoomChanged = Math.abs(Math.log(target.zoom / prevState.zoom)) > 0.01;\n if (panDist < PAN_DEADBAND_VP / 2 && !zoomChanged) {\n prevEnd = shot.outEnd;\n continue;\n }\n\n // Long pans while zoomed read badly: pull wide first, then dive in.\n const viaWide =\n panDist > plane.vpW * 0.6 && prevState.zoom > 1.15 && target.zoom > 1.15 ? wideState : null;\n\n const arriveBy = Math.max(shot.firstBeat - ARRIVE_LEAD_MS, shot.outStart + 100);\n const travel = clamp(300 + panDist * 0.8, TRAVEL_MIN_MS, TRAVEL_MAX_MS);\n let moveStart = Math.max(prevEnd, arriveBy - travel);\n if (viaWide) {\n const mid = Math.max(prevEnd, moveStart - 350);\n kfs.push({ tOut: mid, state: prevState, ease: EASE_PAN });\n kfs.push({ tOut: Math.min(mid + 400, arriveBy - 200), state: viaWide, ease: EASE_ZOOM });\n moveStart = Math.min(mid + 400, arriveBy - 200);\n } else {\n kfs.push({ tOut: moveStart, state: prevState, ease: EASE_PAN });\n }\n const moveEnd = Math.max(arriveBy, moveStart + 250);\n kfs.push({ tOut: moveEnd, state: target, ease: zoomChanged ? EASE_ZOOM : EASE_PAN });\n prevState = target;\n prevEnd = shot.outEnd;\n }\n\n // Final pull-back to wide during the outro.\n if (prevState.zoom > wideState.zoom + 0.01 || Math.hypot(prevState.cx - wideState.cx, prevState.cy - wideState.cy) > PAN_DEADBAND_VP) {\n const start = Math.min(prevEnd + 100, durationMs - 900);\n kfs.push({ tOut: start, state: prevState, ease: EASE_ZOOM });\n kfs.push({ tOut: Math.min(start + 800, durationMs - 50), state: wideState, ease: EASE_ZOOM });\n }\n return dedupeSorted(kfs);\n}\n\nfunction dedupeSorted(kfs: CameraKeyframe[]): CameraKeyframe[] {\n kfs.sort((a, b) => a.tOut - b.tOut);\n const out: CameraKeyframe[] = [];\n for (const kf of kfs) {\n const last = out[out.length - 1];\n if (last && kf.tOut - last.tOut < 1) {\n out[out.length - 1] = kf;\n } else {\n out.push(kf);\n }\n }\n return out;\n}\n\ninterface Violation {\n stepRef: string;\n tOut: number;\n}\n\n/**\n * The \"never crop mid-element\" guarantee: analytically sample the planned path and assert\n * every target is fully in frame (not cropped) during its hold. The comfortable safe-area\n * margin is a preference in shotState, not a hard constraint here.\n */\nfunction checkConstraints(\n keyframes: CameraKeyframe[],\n steps: StepMapEntry[],\n plane: CameraPlane,\n profile: OutputProfile,\n): Violation | null {\n // The camera projects into stage-content space, so the containment frame is the content rect.\n const content = stageContent(profile);\n const frame: Rect = { x: 0, y: 0, w: content.w, h: content.h };\n for (const step of steps) {\n // Windows to validate: an act→react step promises the ACTION target around the beat and the\n // FOCUSED payoff during the settled hold (the camera travels between — unchecked by design).\n // Otherwise: the focused rect (or the target) across the whole hold.\n const handoff = actReactWindows(step);\n const rect = step.focusRectVp ?? step.targetRectVp;\n const windows = handoff\n ? [handoff.act, handoff.react]\n : rect\n ? [{ rect, from: Math.max(step.outStart, step.outBeat - 60), to: step.outEnd }]\n : [];\n for (const w of windows) {\n for (let t = w.from; t <= w.to; t += 100) {\n const cam = sampleCamera(keyframes, t);\n const proj = projectRect(w.rect, cam, plane);\n if (!rectContains(frame, proj, 2)) {\n return { stepRef: step.stepRef, tOut: t };\n }\n }\n }\n }\n return null;\n}\n","import type { CursorSegment, ClickRipple, StepMapEntry } from '../types.js';\nimport type { EventLog } from '../../capture/events.js';\nimport { eventByStepRef } from '../timeline/pacing.js';\nimport { type Point, clamp, dist } from '../../shared/geometry.js';\nimport { minJerk } from '../../shared/easing.js';\n\nconst RESAMPLE_POINTS = 32;\nconst CLICK_KINDS = new Set(['click', 'dblclick', 'select']);\nconst POINTER_KINDS = new Set(['click', 'dblclick', 'hover', 'type', 'select']);\n\nexport interface CursorPlan {\n segments: CursorSegment[];\n ripples: ClickRipple[];\n restStart: Point;\n}\n\n/**\n * Re-synthesize cursor motion on the output clock: recorded waypoints give the path SHAPE,\n * arrival is re-timed so the cursor lands on the target exactly at the action beat with a\n * minimum-jerk profile.\n */\nexport function planCursor(steps: StepMapEntry[], log: EventLog): CursorPlan {\n const events = eventByStepRef(log);\n const segments: CursorSegment[] = [];\n const ripples: ClickRipple[] = [];\n let rest: Point = { x: log.meta.viewport.w / 2, y: log.meta.viewport.h * 0.6 };\n const restStart = { ...rest };\n\n for (const step of steps) {\n if (!POINTER_KINDS.has(step.kind)) continue;\n const event = events.get(step.stepRef);\n if (!event || event.cursorPath.length < 2) continue;\n\n const raw: Point[] = event.cursorPath.map((w) => ({ x: w.x, y: w.y }));\n // Continuity: motion starts wherever the cursor last rested on the output clock.\n raw[0] = { ...rest };\n const path = resampleByArcLength(raw, RESAMPLE_POINTS);\n const travelDist = dist(path[0]!, path[path.length - 1]!);\n const travel = clamp(300 + travelDist * 0.6, 300, 900);\n\n const prevEnd = segments.length > 0 ? segments[segments.length - 1]!.tEnd : 0;\n const tEnd = step.outBeat;\n const tStart = Math.max(Math.min(step.outStart, tEnd - 100), tEnd - travel, prevEnd + 40);\n\n if (tEnd - tStart > 30) {\n segments.push({ tStart, tEnd, path, clickAtEnd: CLICK_KINDS.has(step.kind) });\n }\n rest = path[path.length - 1]!;\n if (CLICK_KINDS.has(step.kind)) {\n ripples.push({ tOut: step.outBeat, x: rest.x, y: rest.y });\n }\n }\n return { segments, ripples, restStart };\n}\n\n/** Position of the cursor at an output time (viewport space). */\nexport function sampleCursor(plan: CursorPlan, tOut: number): Point {\n const segs = plan.segments;\n if (segs.length === 0) return plan.restStart;\n if (tOut <= segs[0]!.tStart) return segs[0]!.path[0]!;\n\n for (let i = 0; i < segs.length; i++) {\n const s = segs[i]!;\n if (tOut < s.tStart) return segs[i - 1]!.path[segs[i - 1]!.path.length - 1]!;\n if (tOut <= s.tEnd) {\n const u = minJerk((tOut - s.tStart) / Math.max(1e-6, s.tEnd - s.tStart));\n const fi = u * (s.path.length - 1);\n const i0 = Math.floor(fi);\n const i1 = Math.min(i0 + 1, s.path.length - 1);\n const f = fi - i0;\n return {\n x: s.path[i0]!.x + (s.path[i1]!.x - s.path[i0]!.x) * f,\n y: s.path[i0]!.y + (s.path[i1]!.y - s.path[i0]!.y) * f,\n };\n }\n }\n const last = segs[segs.length - 1]!;\n return last.path[last.path.length - 1]!;\n}\n\n/** Resample a polyline to n points equally spaced by arc length. */\nfunction resampleByArcLength(points: Point[], n: number): Point[] {\n const cum: number[] = [0];\n for (let i = 1; i < points.length; i++) {\n cum.push(cum[i - 1]! + dist(points[i - 1]!, points[i]!));\n }\n const total = cum[cum.length - 1]!;\n if (total < 1e-6) return Array.from({ length: n }, () => ({ ...points[0]! }));\n const out: Point[] = [];\n let j = 0;\n for (let i = 0; i < n; i++) {\n const target = (i / (n - 1)) * total;\n while (j < cum.length - 2 && cum[j + 1]! < target) j++;\n const span = Math.max(1e-6, cum[j + 1]! - cum[j]!);\n const f = (target - cum[j]!) / span;\n out.push({\n x: points[j]!.x + (points[j + 1]!.x - points[j]!.x) * f,\n y: points[j]!.y + (points[j + 1]!.y - points[j]!.y) * f,\n });\n }\n return out;\n}\n","import type { ActionEvent } from '../capture/events.js';\nimport { parseLocator, locatorDisplayName } from '../spec/locators.js';\n\n/** Per-step text overrides from a LIVE spec, keyed by stepRef — the compose-time source of\n * truth for caption/narration text. The copies baked into events.json are only the record of\n * what was captured; preferring the live spec makes text edits a sub-second re-compose, never\n * a re-capture (capture once, compose forever — including the words). */\nexport interface StepTexts {\n caption?: string;\n narration?: string;\n}\n\n/**\n * Deterministic caption writer: turns a step + its recorded accessible label into\n * instruction text. Text resolution: live-spec caption ?? captured caption ?? auto-written.\n * Returns null for steps that produce no caption (expect/wait without caption).\n */\nexport function writeCaption(event: ActionEvent, texts?: StepTexts): string | null {\n if (texts?.caption) return texts.caption;\n if (event.caption) return event.caption;\n\n const label = bestLabel(event);\n switch (event.kind) {\n case 'click':\n return label ? `Click “${label}”` : 'Click the highlighted element';\n case 'dblclick':\n return label ? `Double-click “${label}”` : 'Double-click the highlighted element';\n case 'hover':\n return label ? `Hover over “${label}”` : 'Hover over the highlighted element';\n case 'type':\n return label ? `Enter the ${lowerFirst(label)}` : 'Enter a value';\n case 'press':\n return `Press ${event.locator ?? 'the key'}`;\n case 'rightclick':\n return label ? `Right-click “${label}”` : 'Right-click the element';\n case 'upload':\n return label ? `Upload a file to ${lowerFirst(label)}` : 'Upload the file';\n case 'drag':\n return label ? `Drag “${label}” into place` : 'Drag the item into place';\n case 'select':\n return label && event.typedText\n ? `Choose “${event.typedText}” under ${label}`\n : label\n ? `Choose an option under ${label}`\n : 'Choose an option';\n case 'goto':\n return `Open ${prettyUrl(event.locator ?? '')}`;\n case 'scroll':\n return label ? `Scroll to ${label}` : 'Scroll down';\n case 'expect':\n case 'wait':\n return null;\n }\n}\n\n/**\n * The SPOKEN line for a step: live-spec narration ?? live-spec caption ?? captured narration ??\n * the caption. Narration is unconstrained by the caption card, so a spec can show a terse\n * on-screen label while the voice says the full sentence.\n */\nexport function writeNarration(event: ActionEvent, texts?: StepTexts): string | null {\n return texts?.narration ?? event.narration ?? writeCaption(event, texts);\n}\n\nfunction bestLabel(event: ActionEvent): string | null {\n const name = event.targetPre?.accessibleName?.trim();\n if (name) return truncate(name, 60);\n if (event.locator) {\n try {\n return truncate(locatorDisplayName(parseLocator(event.locator)), 60);\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction lowerFirst(s: string): string {\n // Keep acronyms/proper-looking tokens intact (\"API key\" stays, \"Email\" lowers).\n if (s.length > 1 && s[1] === s[1]!.toUpperCase() && /[A-Z]/.test(s[1]!)) return s;\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n\nfunction prettyUrl(url: string): string {\n try {\n const u = new URL(url);\n return u.host + (u.pathname !== '/' ? u.pathname : '');\n } catch {\n return url;\n }\n}\n\nfunction truncate(s: string, max: number): string {\n return s.length <= max ? s : s.slice(0, max - 1) + '…';\n}\n","import { createCanvas, type SKRSContext2D } from '@napi-rs/canvas';\n\nlet measureCtx: SKRSContext2D | null = null;\n\nfunction ctx(): SKRSContext2D {\n if (!measureCtx) measureCtx = createCanvas(8, 8).getContext('2d');\n return measureCtx;\n}\n\nexport function measureText(text: string, font: string): number {\n const c = ctx();\n c.font = font;\n return c.measureText(text).width;\n}\n\nexport interface WrapResult {\n lines: string[];\n fontPx: number;\n widest: number;\n shrunk: boolean;\n truncated: boolean;\n}\n\n/**\n * Greedy word-wrap with overflow as a first-class fact: try at fontPx; if the text needs\n * more than maxLines, shrink once to minFontPx; if it still overflows, truncate the last\n * line with an ellipsis AND report it — never silently clip.\n */\nexport function wrapText(\n text: string,\n fontFor: (px: number) => string,\n maxWidth: number,\n fontPx: number,\n minFontPx: number,\n maxLines: number,\n): WrapResult {\n let attempt = wrapAt(text, fontFor(fontPx), maxWidth);\n if (attempt.length <= maxLines) {\n return { lines: attempt, fontPx, widest: widestOf(attempt, fontFor(fontPx)), shrunk: false, truncated: false };\n }\n attempt = wrapAt(text, fontFor(minFontPx), maxWidth);\n if (attempt.length <= maxLines) {\n return { lines: attempt, fontPx: minFontPx, widest: widestOf(attempt, fontFor(minFontPx)), shrunk: true, truncated: false };\n }\n const kept = attempt.slice(0, maxLines);\n let last = kept[maxLines - 1]!;\n const font = fontFor(minFontPx);\n while (last.length > 1 && measureText(last + '…', font) > maxWidth) {\n last = last.slice(0, -1).trimEnd();\n }\n kept[maxLines - 1] = last + '…';\n return { lines: kept, fontPx: minFontPx, widest: widestOf(kept, font), shrunk: true, truncated: true };\n}\n\nfunction wrapAt(text: string, font: string, maxWidth: number): string[] {\n const words = text.split(/\\s+/).filter(Boolean);\n const lines: string[] = [];\n let line = '';\n for (const word of words) {\n const candidate = line ? line + ' ' + word : word;\n if (line && measureText(candidate, font) > maxWidth) {\n lines.push(line);\n line = word;\n } else {\n line = candidate;\n }\n }\n if (line) lines.push(line);\n return lines.length > 0 ? lines : [''];\n}\n\nfunction widestOf(lines: string[], font: string): number {\n return Math.max(...lines.map((l) => measureText(l, font)));\n}\n\n/** Rounded-rect path helper shared by overlay drawing. */\nexport function roundRect(c: SKRSContext2D, x: number, y: number, w: number, h: number, r: number): void {\n const rr = Math.min(r, w / 2, h / 2);\n c.beginPath();\n c.moveTo(x + rr, y);\n c.arcTo(x + w, y, x + w, y + h, rr);\n c.arcTo(x + w, y + h, x, y + h, rr);\n c.arcTo(x, y + h, x, y, rr);\n c.arcTo(x, y, x + w, y, rr);\n c.closePath();\n}\n","import type { CameraKeyframe, CaptionOverlay, ComposeDiagnostics, OutputProfile, OverlayEntry, StepMapEntry } from '../types.js';\nimport { stageContent, actReactWindows } from '../types.js';\nimport type { EventLog } from '../../capture/events.js';\nimport type { ResolvedTheme } from '../../theme/index.js';\nimport type { KindProfile } from '../kinds.js';\nimport { writeCaption, type StepTexts } from '../captions.js';\nimport { eventByStepRef } from '../timeline/pacing.js';\nimport { wrapText, measureText } from './text.js';\nimport { sampleCamera } from '../camera/interpolate.js';\nimport { projectRect, type CameraPlane, type Rect } from '../../shared/geometry.js';\n\nconst CARD_PAD_X = 26;\nconst CARD_PAD_Y = 16;\nconst BADGE_GAP = 14;\nconst CARD_BOTTOM_MARGIN = 44;\nconst CHAPTER_LABEL_MS = 1800;\n/** Adjacent captions overlap by this much and cross-dissolve (fade handles the blend). */\nconst CAPTION_CROSSFADE_MS = 240;\n\nfunction overlaps(a: Rect, b: Rect): boolean {\n return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;\n}\n\nexport function buildOverlays(\n steps: StepMapEntry[],\n log: EventLog,\n theme: ResolvedTheme,\n profile: OutputProfile,\n title: string,\n subtitle: string,\n titleCardEndMs: number,\n diagnostics: ComposeDiagnostics,\n kind: KindProfile,\n sceneTitles?: Map<string, string>,\n camera?: CameraKeyframe[],\n specTexts?: Map<string, StepTexts>,\n): OverlayEntry[] {\n const overlays: OverlayEntry[] = [];\n overlays.push({ kind: 'titleCard', cardId: 'title', title, subtitle, tStart: 0, tEnd: titleCardEndMs });\n overlays.push({ kind: 'dip', tStart: titleCardEndMs, tEnd: titleCardEndMs + 400 });\n\n const events = eventByStepRef(log);\n const captioned = steps.filter((s) => {\n const e = events.get(s.stepRef);\n return e && writeCaption(e, specTexts?.get(s.stepRef)) !== null;\n });\n const total = captioned.length;\n let number = 0;\n\n // Chapter labels at each new scene, and an elapsed clock spanning the flow (bug-repro).\n if (kind.chapterCards) {\n const boundaries = sceneBoundaries(steps, sceneTitles);\n let chapter = 0;\n for (const b of boundaries) {\n chapter += 1;\n overlays.push({ kind: 'chapterLabel', title: b.title, ordinal: chapter, tStart: b.outStart, tEnd: b.outStart + CHAPTER_LABEL_MS });\n }\n }\n if (kind.elapsedClock) {\n const firstBeat = captioned[0]?.outBeat ?? titleCardEndMs;\n const last = steps[steps.length - 1];\n overlays.push({ kind: 'elapsedClock', tStart: titleCardEndMs, tEnd: last ? last.outEnd : titleCardEndMs, zeroAtMs: firstBeat });\n }\n\n // `captions: off` renders no caption cards (used for the voice-only cut); the\n // spoken narration still comes from the same text, derived separately in compose.\n for (let i = 0; theme.captionPosition !== 'off' && i < captioned.length; i++) {\n const step = captioned[i]!;\n const event = events.get(step.stepRef)!;\n const base = writeCaption(event, specTexts?.get(step.stepRef))!;\n number += 1;\n const text = kind.captionStyle === 'factual' ? `Step ${number} — ${lowerFirst(base)}` : base;\n\n const fontFor = (px: number) => `${px}px Inter Medium`;\n const showBadge = kind.numberedCaptions && kind.captionStyle !== 'factual';\n // Everything scales with the profile's uiScale so custom resolutions (720p, 4K, portrait)\n // keep the 1080-class proportions (round-2 audit: fixed px broke at every other size).\n const ui = profile.uiScale;\n const padX = Math.round(CARD_PAD_X * ui);\n const padY = Math.round(CARD_PAD_Y * ui);\n const badgeFontPx = Math.max(11, Math.round(15 * ui));\n const badgeText = `${number}/${total}`;\n const badgeW = showBadge ? Math.ceil(measureText(badgeText, `600 ${badgeFontPx}px Inter SemiBold`)) + Math.round(20 * ui) : 0;\n const badgeGap = showBadge ? Math.round(BADGE_GAP * ui) : 0;\n const maxTextWidth = Math.min(profile.captionMaxWidth, profile.width - 2 * profile.safeArea.left) - padX * 2 - badgeW - badgeGap;\n\n const wrap = wrapText(\n text,\n fontFor,\n maxTextWidth,\n Math.round(theme.captionFontPx * ui),\n Math.round(theme.captionMinFontPx * ui),\n theme.captionMaxLines,\n );\n if (wrap.truncated) diagnostics.overflows.push({ stepRef: step.stepRef, text, action: 'truncated' });\n else if (wrap.shrunk) diagnostics.overflows.push({ stepRef: step.stepRef, text, action: 'shrunk' });\n\n const lineH = Math.round(wrap.fontPx * 1.35);\n const cardW = padX * 2 + badgeW + badgeGap + Math.ceil(wrap.widest);\n const cardH = padY * 2 + wrap.lines.length * lineH;\n const x = (profile.width - cardW) / 2;\n let y =\n theme.captionPosition === 'bottom'\n ? profile.height - Math.round(CARD_BOTTOM_MARGIN * ui) - cardH\n : profile.safeArea.top;\n\n // Collision flip: if the framed subject sits under the caption during the hold, move the\n // caption to the top rather than covering the very thing the step is about.\n if (camera && theme.captionPosition === 'bottom') {\n const content = stageContent(profile);\n const capPlane: CameraPlane = { vpW: log.meta.viewport.w, vpH: log.meta.viewport.h, outW: content.w, outH: content.h };\n const capBox: Rect = { x, y, w: cardW, h: cardH };\n // Evaluate each framing window against ITS OWN camera: an act→react step frames the\n // target at the beat and the payoff only after the handoff — projecting the payoff\n // through the beat camera made the flip decision meaningless (round-2 audit).\n const handoff = actReactWindows(step);\n const probes = handoff\n ? [\n { rect: handoff.act.rect, t: Math.min(step.outBeat + 250, handoff.act.to) },\n { rect: handoff.react.rect, t: handoff.react.from + 50 },\n ]\n : step.focusRectVp ?? step.targetRectVp\n ? [{ rect: (step.focusRectVp ?? step.targetRectVp)!, t: Math.min(step.outBeat + 250, step.outEnd) }]\n : [];\n for (const probe of probes) {\n const cam = sampleCamera(camera, probe.t);\n const proj = projectRect(probe.rect, cam, capPlane);\n const projFrame: Rect = { x: proj.x + content.x, y: proj.y + content.y, w: proj.w, h: proj.h };\n if (overlaps(projFrame, capBox)) {\n y = profile.safeArea.top;\n break;\n }\n }\n }\n\n // Caption runs slightly INTO the next caption's window so adjacent captions cross-dissolve\n // instead of blinking out to an empty band at every step boundary.\n const next = captioned[i + 1];\n const tEnd = next ? Math.min(step.outEnd, next.outStart + CAPTION_CROSSFADE_MS) : step.outEnd;\n\n const overlay: CaptionOverlay = {\n kind: 'caption',\n stepRef: step.stepRef,\n ordinal: number,\n totalSteps: total,\n showBadge,\n text,\n lines: wrap.lines,\n fontPx: wrap.fontPx,\n box: { x, y, w: cardW, h: cardH },\n tStart: step.outStart,\n tEnd,\n shrunk: wrap.shrunk,\n truncated: wrap.truncated,\n };\n overlays.push(overlay);\n }\n return overlays;\n}\n\n/** First step of each scene, with a human title, for chapter labels. The spec's own\n * `scene.title` wins; deriving from the kebab-case id is only the fallback. */\nfunction sceneBoundaries(\n steps: StepMapEntry[],\n sceneTitles?: Map<string, string>,\n): { title: string; outStart: number }[] {\n const out: { title: string; outStart: number }[] = [];\n let lastScene = '';\n for (const s of steps) {\n if (s.sceneId !== lastScene) {\n lastScene = s.sceneId;\n out.push({ title: sceneTitles?.get(s.sceneId) ?? titleFromSceneId(s.sceneId), outStart: s.outStart });\n }\n }\n return out;\n}\n\nfunction titleFromSceneId(id: string): string {\n const t = id.replace(/-/g, ' ');\n return t.charAt(0).toUpperCase() + t.slice(1);\n}\n\nfunction lowerFirst(s: string): string {\n if (s.length > 1 && s[1] === s[1]!.toUpperCase() && /[A-Z]/.test(s[1]!)) return s;\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n","import { createCanvas, type Canvas, type SKRSContext2D } from '@napi-rs/canvas';\nimport type { BundleData } from '../../bundle/types.js';\nimport type { ComposeManifest, TitleCardOverlay, StepMapEntry } from '../types.js';\nimport { stageContent } from '../types.js';\nimport { sampleSource } from '../timeline/pacing.js';\nimport { sampleCamera } from '../camera/interpolate.js';\nimport { sampleCursor, type CursorPlan } from '../cursor/path.js';\nimport { drawCursor, type CursorGlyph } from '../cursor/render.js';\nimport { drawOverlays, drawTitleCard, drawFailureCard } from '../overlays/draw.js';\nimport { roundRect } from '../overlays/text.js';\nimport { visibleRect, projectPoint, projectRect, clamp, type CameraPlane, type Rect } from '../../shared/geometry.js';\nimport { FrameStore } from './frameStore.js';\nimport { Encoder } from './encoder.js';\nimport { registerFonts } from '../../theme/index.js';\nimport { log } from '../../shared/log.js';\n\nconst SPOTLIGHT_KINDS = new Set(['click', 'dblclick', 'select']);\nconst SPOTLIGHT_LEAD_MS = 200;\nconst SPOTLIGHT_TAIL_MS = 650;\n/** A click that DISMISSES its own target (suggestion pick, menu item): the spotlight ends with\n * the ripple — a 650ms tail would illuminate the empty region where the element used to be\n * (user-reported on the Wikipedia search-suggestion demo). */\nconst SPOTLIGHT_TAIL_GONE_MS = 160;\nconst SPOTLIGHT_MAX_DIM = 0.34;\n\n/** Render the full output from a bundle + compose manifest. Pure playback of the plan. */\nexport async function renderVideo(\n bundle: BundleData,\n manifest: ComposeManifest,\n outPath: string,\n): Promise<void> {\n registerFonts();\n const { profile, theme } = manifest;\n const { width, height, fps } = profile;\n // All camera math runs in stage-content space (the same space the planner and verifier use);\n // the renderer's only extra job is translating that space onto the frame at `content.x/y`.\n const content = stageContent(profile);\n const plane: CameraPlane = {\n vpW: manifest.viewport.w,\n vpH: manifest.viewport.h,\n outW: content.w,\n outH: content.h,\n };\n const frameScale = bundle.manifest.frameW / manifest.viewport.w;\n\n const store = new FrameStore(bundle);\n const encoder = new Encoder(outPath, width, height, fps);\n const canvas = createCanvas(width, height);\n const ctx = canvas.getContext('2d');\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = 'high';\n // Offscreen scratch for the spotlight (dim layer with a feathered punch-out).\n const spotCanvas = createCanvas(content.w, content.h);\n const spotCtx = spotCanvas.getContext('2d');\n\n const cursorPlan: CursorPlan = {\n segments: manifest.cursor,\n ripples: manifest.ripples,\n restStart:\n manifest.cursor.length > 0\n ? manifest.cursor[0]!.path[0]!\n : { x: manifest.viewport.w / 2, y: manifest.viewport.h * 0.6 },\n };\n const cards = new Map(\n manifest.overlays\n .filter((o): o is TitleCardOverlay => o.kind === 'titleCard')\n .map((c) => [c.cardId, c]),\n );\n const transitions = manifest.transitions ?? [];\n // Spotlight the ACTION TARGET at the beat — the camera is framing the click there, and for\n // act→react steps the payoff rect may be off-screen at the beat (the old focusRect-first\n // order dimmed the click under its own spotlight; round-2 audit).\n const spotlightSteps = manifest.steps.filter(\n (s) => SPOTLIGHT_KINDS.has(s.kind) && (s.targetRectVp ?? s.focusRectVp),\n );\n\n const start = Date.now();\n for (let i = 0; i < manifest.totalFrames; i++) {\n const tOut = (i * 1000) / fps;\n const { srcAt, segment } = sampleSource(manifest.segments, tOut);\n\n if (srcAt === null) {\n const failCard =\n segment.kind === 'card' && segment.cardId === 'failure'\n ? manifest.overlays.find((o) => o.kind === 'failureCard')\n : undefined;\n const card = segment.kind === 'card' ? cards.get(segment.cardId) : undefined;\n if (failCard && failCard.kind === 'failureCard') drawFailureCard(ctx, failCard, tOut, theme, profile);\n else if (card) drawTitleCard(ctx, card, tOut, theme, profile);\n else {\n ctx.fillStyle = theme.bg;\n ctx.fillRect(0, 0, width, height);\n }\n } else {\n const cam = sampleCamera(manifest.camera, tOut);\n const vis = visibleRect(cam, plane);\n\n // ---- the stage: matte background + card (chrome bar + footage) ----\n paintStageBackdrop(ctx, profile, theme);\n ctx.save();\n if (profile.stage) {\n paintStageCard(ctx, profile, theme, bundle.manifest.appUrl);\n roundRect(ctx, content.x, content.y, content.w, content.h, 0); // content area (card carries the radius)\n ctx.clip();\n }\n\n // ---- footage: frame blending kills 20→30fps judder during real motion ----\n const drawSrc = (img: Canvas, alpha: number) => {\n ctx.globalAlpha = alpha;\n ctx.drawImage(\n img,\n vis.x * frameScale, vis.y * frameScale, vis.w * frameScale, vis.h * frameScale,\n content.x, content.y, content.w, content.h,\n );\n ctx.globalAlpha = 1;\n };\n const pair = await store.framePairForTime(srcAt);\n // Blend only inside `source` segments playing at ~natural rate: blending across a freeze\n // would ghost the NEXT action into a hold, and blending inside a sped-up idle gap (25x)\n // flickers — the gap check is SOURCE time, which says nothing about playback rate.\n const rate =\n segment.kind === 'source'\n ? (segment.srcEnd - segment.srcStart) / Math.max(1, segment.outEnd - segment.outStart)\n : Infinity;\n if (segment.kind === 'source' && rate < 1.5 && pair.b && pair.mix > 0.12 && pair.gapMs < 400) {\n drawSrc(pair.a, 1);\n drawSrc(pair.b, pair.mix);\n } else {\n drawSrc(pair.a, 1);\n }\n\n // ---- scene-boundary cross-dissolve: old footage fades into the new scene ----\n const tr = transitions.find((w) => tOut >= w.tStart && tOut <= w.tEnd);\n if (tr) {\n const u = clamp((tOut - tr.tStart) / Math.max(1, tr.tEnd - tr.tStart), 0, 1);\n if (u < 1) {\n const from = await store.frameForTime(tr.srcFrom);\n drawSrc(from, 1 - u);\n }\n }\n\n // ---- click spotlight: dim the surroundings, feather-punch the target ----\n const spot = activeSpotlight(spotlightSteps, tOut);\n if (spot) {\n const rect = spot.step.targetRectVp ?? spot.step.focusRectVp!;\n const proj = projectRect(rect, cam, plane);\n drawSpotlight(spotCtx, content, proj, spot.alpha);\n ctx.drawImage(spotCanvas, content.x, content.y);\n }\n\n // Cursor + ripples live on the source plane; project through the camera, then translate\n // into frame space by the stage origin.\n const cursorVp = sampleCursor(cursorPlan, tOut);\n const cursorOut = projectPoint(cursorVp, cam, plane);\n const rippleCenters = manifest.ripples.map((r) => {\n const p = projectPoint({ x: r.x, y: r.y }, cam, plane);\n return { x: p.x + content.x, y: p.y + content.y };\n });\n const glyph = cursorGlyphAt(manifest.steps, tOut);\n drawCursor(\n ctx,\n { x: cursorOut.x + content.x, y: cursorOut.y + content.y },\n cam.zoom,\n tOut,\n manifest.ripples,\n rippleCenters,\n theme,\n plane.outW / plane.vpW,\n glyph,\n );\n ctx.restore();\n }\n\n drawOverlays(ctx, manifest.overlays, tOut, theme, profile);\n await encoder.write(Buffer.from(ctx.getImageData(0, 0, width, height).data.buffer));\n\n if (i > 0 && i % 300 === 0) {\n const fpsNow = i / ((Date.now() - start) / 1000);\n log.debug(`rendered ${i}/${manifest.totalFrames} frames (${fpsNow.toFixed(0)} fps)`);\n }\n }\n await encoder.finish();\n const elapsed = (Date.now() - start) / 1000;\n log.ok(\n `rendered ${manifest.totalFrames} frames in ${elapsed.toFixed(1)}s (${(manifest.totalFrames / elapsed).toFixed(0)} fps) → ${outPath}`,\n );\n}\n\n/** Soft vertical gradient behind the stage, derived from the theme. */\nfunction paintStageBackdrop(ctx: SKRSContext2D, profile: { width: number; height: number }, theme: { bg: string; bgSubtle: string }): void {\n const g = ctx.createLinearGradient(0, 0, 0, profile.height);\n g.addColorStop(0, theme.bgSubtle);\n g.addColorStop(1, theme.bg);\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, profile.width, profile.height);\n}\n\n/** The card: shadow, rounded body, browser-chrome bar (traffic dots + URL pill). */\nfunction paintStageCard(\n ctx: SKRSContext2D,\n profile: { stage?: { content: Rect; chromeH: number; radius: number }; width: number },\n theme: { surface: string; onSurfaceDim: string },\n appUrl: string,\n): void {\n const s = profile.stage!;\n const c = s.content;\n const cardX = c.x;\n const cardY = c.y - s.chromeH;\n const cardW = c.w;\n const cardH = c.h + s.chromeH;\n\n ctx.save();\n ctx.shadowColor = 'rgba(0,0,0,0.45)';\n ctx.shadowBlur = 42;\n ctx.shadowOffsetY = 14;\n ctx.fillStyle = '#20242e';\n roundRect(ctx, cardX, cardY, cardW, cardH, s.radius);\n ctx.fill();\n ctx.restore();\n\n if (s.chromeH > 0) {\n // Traffic dots\n const dotY = cardY + s.chromeH / 2;\n const dotR = Math.max(5, Math.round(s.chromeH * 0.14));\n const colors = ['#ff5f57', '#febc2e', '#28c840'];\n colors.forEach((col, i) => {\n ctx.fillStyle = col;\n ctx.beginPath();\n ctx.arc(cardX + 24 + i * (dotR * 2 + 9), dotY, dotR, 0, Math.PI * 2);\n ctx.fill();\n });\n // URL pill\n const url = displayUrl(appUrl);\n const pillH = Math.round(s.chromeH * 0.62);\n ctx.font = `500 ${Math.round(pillH * 0.52)}px Inter Medium`;\n const textW = ctx.measureText(url).width;\n const pillW = Math.min(cardW * 0.5, textW + 36);\n const pillX = cardX + (cardW - pillW) / 2;\n const pillY = cardY + (s.chromeH - pillH) / 2;\n ctx.fillStyle = 'rgba(255,255,255,0.08)';\n roundRect(ctx, pillX, pillY, pillW, pillH, pillH / 2);\n ctx.fill();\n ctx.fillStyle = 'rgba(255,255,255,0.55)';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(url, pillX + pillW / 2, pillY + pillH / 2 + 1, pillW - 24);\n }\n}\n\nfunction displayUrl(appUrl: string): string {\n try {\n const u = new URL(appUrl);\n return u.host + (u.pathname !== '/' ? u.pathname : '');\n } catch {\n return appUrl;\n }\n}\n\n/** Which spotlight (if any) is active at tOut, with its ramped alpha. */\nfunction activeSpotlight(\n steps: StepMapEntry[],\n tOut: number,\n): { step: StepMapEntry; alpha: number } | null {\n for (const step of steps) {\n const tail = step.targetGone ? SPOTLIGHT_TAIL_GONE_MS : SPOTLIGHT_TAIL_MS;\n const from = step.outBeat - SPOTLIGHT_LEAD_MS;\n const to = step.outBeat + tail;\n if (tOut < from || tOut > to) continue;\n const rampIn = clamp((tOut - from) / 180, 0, 1);\n const rampOut = clamp((to - tOut) / Math.min(250, tail), 0, 1);\n return { step, alpha: SPOTLIGHT_MAX_DIM * Math.min(rampIn, rampOut) };\n }\n return null;\n}\n\n/** Dim layer with a feathered punch-out around the target, built on the scratch canvas. */\nfunction drawSpotlight(sctx: SKRSContext2D, content: Rect, proj: Rect, alpha: number): void {\n sctx.clearRect(0, 0, content.w, content.h);\n sctx.fillStyle = `rgba(6,8,14,${alpha.toFixed(3)})`;\n sctx.fillRect(0, 0, content.w, content.h);\n const pad = 14;\n sctx.save();\n sctx.globalCompositeOperation = 'destination-out';\n sctx.shadowColor = '#ffffff';\n sctx.shadowBlur = 30;\n sctx.fillStyle = '#ffffff';\n roundRect(sctx, proj.x - pad, proj.y - pad, proj.w + pad * 2, proj.h + pad * 2, 10);\n sctx.fill();\n sctx.restore();\n}\n\n/** Glyph for the active step: I-beam while typing, arrow otherwise. */\nfunction cursorGlyphAt(steps: StepMapEntry[], tOut: number): CursorGlyph {\n for (const s of steps) {\n if (s.kind === 'type' && tOut >= s.outStart && tOut <= s.outEnd) return 'ibeam';\n }\n return 'arrow';\n}\n","import type { SKRSContext2D } from '@napi-rs/canvas';\nimport type { Point } from '../../shared/geometry.js';\nimport type { ClickRipple } from '../types.js';\nimport type { ResolvedTheme } from '../../theme/index.js';\n\nconst RIPPLE_MS = 350;\nconst PRESS_DOWN_MS = 90;\nconst PRESS_UP_MS = 120;\n\nexport type CursorGlyph = 'arrow' | 'ibeam';\n\n/** Draw the vector cursor at an output-space point.\n * `baseScale` (output px per viewport px) keeps the cursor proportioned to the UI it points\n * at — without it the cursor renders 1.5× too small against upscaled content. */\nexport function drawCursor(\n ctx: SKRSContext2D,\n p: Point,\n zoom: number,\n tOut: number,\n ripples: ClickRipple[],\n rippleCenters: Point[],\n theme: ResolvedTheme,\n baseScale = 1,\n glyph: CursorGlyph = 'arrow',\n): void {\n // Press animation: scale dips to 0.85 around each click beat.\n let scale = 1;\n for (const r of ripples) {\n const dt = tOut - r.tOut;\n if (dt >= -PRESS_DOWN_MS && dt < 0) scale = 1 - 0.15 * (1 + dt / PRESS_DOWN_MS);\n else if (dt >= 0 && dt <= PRESS_UP_MS) scale = 0.85 + 0.15 * (dt / PRESS_UP_MS);\n }\n\n // Expanding ring at click points (drawn under the cursor).\n for (let i = 0; i < ripples.length; i++) {\n const r = ripples[i]!;\n const dt = tOut - r.tOut;\n if (dt < 0 || dt > RIPPLE_MS) continue;\n const u = dt / RIPPLE_MS;\n const c = rippleCenters[i]!;\n ctx.save();\n ctx.beginPath();\n ctx.arc(c.x, c.y, (6 + 42 * easeOut(u)) * baseScale, 0, Math.PI * 2);\n ctx.strokeStyle = theme.accent;\n ctx.globalAlpha = 0.6 * (1 - u);\n ctx.lineWidth = 3.5 * baseScale * (1 - u * 0.5);\n ctx.stroke();\n ctx.restore();\n }\n\n const size = 24 * baseScale * (1 + 0.15 * (zoom - 1)) * scale;\n ctx.save();\n ctx.translate(p.x, p.y);\n ctx.scale(size / 24, size / 24);\n ctx.shadowColor = 'rgba(0,0,0,0.35)';\n ctx.shadowBlur = 5;\n ctx.shadowOffsetY = 1.5;\n if (glyph === 'ibeam') {\n // I-beam (text) cursor, hotspot at the beam center.\n ctx.beginPath();\n ctx.moveTo(-4, -9);\n ctx.lineTo(4, -9);\n ctx.moveTo(0, -9);\n ctx.lineTo(0, 9);\n ctx.moveTo(-4, 9);\n ctx.lineTo(4, 9);\n ctx.lineWidth = 2.4;\n ctx.strokeStyle = '#ffffff';\n ctx.stroke();\n ctx.shadowColor = 'transparent';\n ctx.lineWidth = 1;\n ctx.strokeStyle = 'rgba(20,24,34,0.9)';\n ctx.stroke();\n } else {\n // Arrow pointer path (24px design grid, hotspot at 0,0)\n ctx.beginPath();\n ctx.moveTo(0, 0);\n ctx.lineTo(0, 17.5);\n ctx.lineTo(4.2, 13.6);\n ctx.lineTo(7.4, 20.6);\n ctx.lineTo(10.3, 19.2);\n ctx.lineTo(7.2, 12.4);\n ctx.lineTo(12.8, 12.2);\n ctx.closePath();\n ctx.fillStyle = '#ffffff';\n ctx.fill();\n ctx.shadowColor = 'transparent';\n ctx.lineWidth = 1.4;\n ctx.strokeStyle = 'rgba(20,24,34,0.9)';\n ctx.stroke();\n }\n ctx.restore();\n}\n\nfunction easeOut(u: number): number {\n return 1 - (1 - u) * (1 - u);\n}\n","import type { SKRSContext2D } from '@napi-rs/canvas';\nimport type { CaptionOverlay, OutputProfile, OverlayEntry, TitleCardOverlay } from '../types.js';\nimport type { ResolvedTheme } from '../../theme/index.js';\nimport { roundRect, measureText } from './text.js';\nimport { clamp } from '../../shared/geometry.js';\n\nconst FADE_MS = 200;\nconst SCRIM_H = 210; // design px @1080; scaled by profile.uiScale at draw\n\nexport function drawOverlays(\n ctx: SKRSContext2D,\n overlays: OverlayEntry[],\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n // Bottom gradient scrim behind the caption band, drawn ONCE at the strongest active caption's\n // alpha (overlapping cross-fading captions must not double-darken it). Keeps caption text off\n // raw UI pixels regardless of what the app renders down there.\n const bottomCaptions = overlays.filter(\n (o): o is CaptionOverlay =>\n o.kind === 'caption' && tOut >= o.tStart && tOut <= o.tEnd && o.box.y > profile.height / 2,\n );\n if (bottomCaptions.length > 0) {\n const a = Math.max(...bottomCaptions.map((o) => captionAlpha(o, tOut)));\n if (a > 0) {\n const scrimH = Math.round(SCRIM_H * profile.uiScale);\n const g = ctx.createLinearGradient(0, profile.height - scrimH, 0, profile.height);\n g.addColorStop(0, 'rgba(8,10,16,0)');\n g.addColorStop(1, `rgba(8,10,16,${(0.55 * a).toFixed(3)})`);\n ctx.fillStyle = g;\n ctx.fillRect(0, profile.height - scrimH, profile.width, scrimH);\n }\n }\n\n // Captions draw as a GROUP: when two adjacent captions cross-fade, render ONE card whose\n // rect lerps between their sizes and swap the text — two half-transparent cards of different\n // widths stacked in the same spot read as a smudge (round-2 audit craft note).\n const activeCaps = overlays.filter(\n (o): o is CaptionOverlay => o.kind === 'caption' && tOut >= o.tStart && tOut <= o.tEnd && captionAlpha(o, tOut) > 0,\n );\n if (activeCaps.length === 2 && activeCaps[0]!.box.y === activeCaps[1]!.box.y) {\n const [a, b] = activeCaps[0]!.tStart <= activeCaps[1]!.tStart ? [activeCaps[0]!, activeCaps[1]!] : [activeCaps[1]!, activeCaps[0]!];\n // Progress of the swap = the incoming caption's fade-in.\n const u = captionAlpha(b, tOut);\n const box = {\n x: a.box.x + (b.box.x - a.box.x) * u,\n y: a.box.y,\n w: a.box.w + (b.box.w - a.box.w) * u,\n h: Math.max(a.box.h, b.box.h),\n };\n drawCaptionCard(ctx, box, 1, theme);\n drawCaptionContent(ctx, a, box, 1 - u, theme);\n drawCaptionContent(ctx, b, box, u, theme);\n } else {\n for (const o of activeCaps) drawCaption(ctx, o, tOut, theme);\n }\n\n for (const o of overlays) {\n if (tOut < o.tStart || tOut > o.tEnd) continue;\n switch (o.kind) {\n case 'caption':\n break; // handled by the grouped pass above\n case 'dip': {\n // 'in': fade from theme bg into footage (post-title). 'out': fade footage into the bg\n // (pre-end-card), so the closing card doesn't hard-cut in.\n const u = (tOut - o.tStart) / Math.max(1, o.tEnd - o.tStart);\n ctx.save();\n ctx.globalAlpha = o.direction === 'out' ? u : 1 - u;\n ctx.fillStyle = theme.bg;\n ctx.fillRect(0, 0, profile.width, profile.height);\n ctx.restore();\n break;\n }\n case 'elapsedClock':\n drawElapsedClock(ctx, o.zeroAtMs, tOut, theme, profile);\n break;\n case 'chapterLabel':\n drawChapterLabel(ctx, o, tOut, theme, profile);\n break;\n case 'titleCard':\n case 'failureCard':\n // Painted by the renderer as a full-frame card (not an overlay on footage).\n break;\n }\n }\n}\n\nfunction drawElapsedClock(\n ctx: SKRSContext2D,\n zeroAtMs: number,\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n const ms = Math.max(0, tOut - zeroAtMs);\n const s = Math.floor(ms / 1000);\n const label = `${String(Math.floor(s / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}.${String(Math.floor((ms % 1000) / 100))}`;\n const ui = profile.uiScale;\n const font = `600 ${Math.round(26 * ui)}px Inter SemiBold`;\n ctx.save();\n ctx.font = font;\n const textW = ctx.measureText(label).width;\n const padX = 16 * ui;\n const w = textW + padX * 2 + 30 * ui;\n const h = 44 * ui;\n const x = profile.width - profile.safeArea.right - w;\n const y = profile.safeArea.top;\n ctx.fillStyle = 'rgba(18,22,31,0.82)';\n roundRect(ctx, x, y, w, h, 10);\n ctx.fill();\n // A small \"recording\" dot.\n ctx.fillStyle = '#ef4444';\n ctx.beginPath();\n ctx.arc(x + padX + 6 * ui, y + h / 2, 6 * ui, 0, Math.PI * 2);\n ctx.fill();\n ctx.fillStyle = '#ffffff';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.font = font;\n ctx.fillText(label, x + padX + 24 * ui, y + h / 2 + 1);\n ctx.restore();\n}\n\nfunction drawChapterLabel(\n ctx: SKRSContext2D,\n o: { title: string; ordinal: number; tStart: number; tEnd: number },\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n const alpha = clamp(Math.min((tOut - o.tStart) / 260, (o.tEnd - tOut) / 320), 0, 1);\n if (alpha <= 0) return;\n ctx.save();\n ctx.globalAlpha = alpha;\n const ui = profile.uiScale;\n const font = `700 ${Math.round(30 * ui)}px Inter Bold`;\n ctx.font = font;\n const textW = ctx.measureText(o.title).width;\n const barW = textW + 96 * ui;\n const barH = 56 * ui;\n const x = (profile.width - barW) / 2;\n // Below the stage's chrome bar (never over the URL pill); safe-area top otherwise.\n const y = profile.stage ? profile.stage.content.y + 14 : profile.safeArea.top + 8;\n ctx.fillStyle = theme.accent;\n roundRect(ctx, x, y, barW, barH, 12);\n ctx.fill();\n ctx.fillStyle = '#ffffff';\n ctx.font = `600 ${Math.round(16 * ui)}px Inter SemiBold`;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(String(o.ordinal), x + 22 * ui, y + barH / 2 + 1);\n ctx.font = font;\n ctx.fillText(o.title, x + 48 * ui, y + barH / 2 + 1);\n ctx.restore();\n}\n\nfunction captionAlpha(o: CaptionOverlay, tOut: number): number {\n return clamp(Math.min((tOut - o.tStart) / FADE_MS, (o.tEnd - tOut) / FADE_MS), 0, 1);\n}\n\nfunction drawCaption(ctx: SKRSContext2D, o: CaptionOverlay, tOut: number, theme: ResolvedTheme): void {\n const alpha = captionAlpha(o, tOut);\n if (alpha <= 0) return;\n ctx.save();\n ctx.globalAlpha = alpha;\n drawCaptionCard(ctx, o.box, 1, theme);\n ctx.restore();\n drawCaptionContent(ctx, o, o.box, alpha, theme);\n}\n\n/** Just the card surface (shadow + rounded rect) at the given box. */\nfunction drawCaptionCard(\n ctx: SKRSContext2D,\n box: { x: number; y: number; w: number; h: number },\n alpha: number,\n theme: ResolvedTheme,\n): void {\n ctx.save();\n ctx.globalAlpha = alpha;\n ctx.shadowColor = 'rgba(0,0,0,0.30)';\n ctx.shadowBlur = 18;\n ctx.shadowOffsetY = 4;\n ctx.fillStyle = theme.surface;\n roundRect(ctx, box.x, box.y, box.w, box.h, theme.radius);\n ctx.fill();\n ctx.restore();\n}\n\n/** Badge + text, anchored to the GIVEN box (which may be a lerped swap box). */\nfunction drawCaptionContent(\n ctx: SKRSContext2D,\n o: CaptionOverlay,\n box: { x: number; y: number; w: number; h: number },\n alpha: number,\n theme: ResolvedTheme,\n): void {\n if (alpha <= 0) return;\n ctx.save();\n ctx.globalAlpha = alpha;\n\n // Step badge chip (omitted for styles that don't number captions)\n let badgeW = 0;\n const bx = box.x + 26;\n if (o.showBadge) {\n const badgeText = `${o.ordinal}/${o.totalSteps}`;\n const bScale = o.fontPx / 36; // badge scales with the (already ui-scaled) caption font\n const badgeFont = `600 ${Math.max(11, Math.round(15 * bScale))}px Inter SemiBold`;\n badgeW = Math.ceil(measureText(badgeText, badgeFont)) + Math.round(20 * bScale);\n const badgeH = Math.round(26 * bScale);\n const by = box.y + box.h / 2 - badgeH / 2;\n ctx.fillStyle = theme.accent;\n roundRect(ctx, bx, by, badgeW, badgeH, 13);\n ctx.fill();\n ctx.fillStyle = '#ffffff';\n ctx.font = badgeFont;\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'center';\n ctx.fillText(badgeText, bx + badgeW / 2, by + badgeH / 2 + 1);\n }\n\n // Caption text\n const lineH = Math.round(o.fontPx * 1.35);\n const textX = o.showBadge ? bx + badgeW + 14 : bx;\n const textTop = box.y + (box.h - o.lines.length * lineH) / 2;\n ctx.fillStyle = theme.onSurface;\n ctx.font = `${o.fontPx}px Inter Medium`;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n o.lines.forEach((line, i) => {\n ctx.fillText(line, textX, textTop + i * lineH + lineH / 2 + 1);\n });\n ctx.restore();\n}\n\n/** The failure clip's closing card: what step broke and why, in evidence red. */\nexport function drawFailureCard(\n ctx: SKRSContext2D,\n card: { stepRef: string; message: string; tStart: number },\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n const { width, height } = profile;\n const g = ctx.createLinearGradient(0, 0, 0, height);\n g.addColorStop(0, '#1c1114');\n g.addColorStop(1, '#12090b');\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, width, height);\n\n const t = tOut - card.tStart;\n const a = clamp(t / 300, 0, 1);\n ctx.save();\n ctx.globalAlpha = a;\n\n ctx.fillStyle = '#ef4444';\n roundRect(ctx, width / 2 - 32, height / 2 - 150, 64, 8, 4);\n ctx.fill();\n\n const uiF = profile.uiScale;\n ctx.fillStyle = '#ffffff';\n ctx.font = `${Math.round(52 * uiF)}px Inter Bold`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText('Flow failed', width / 2, height / 2 - 70);\n\n ctx.fillStyle = '#fca5a5';\n ctx.font = `600 ${Math.round(30 * uiF)}px Inter SemiBold`;\n ctx.fillText(`at step ${card.stepRef}`, width / 2, height / 2 - 12);\n\n // Error message, wrapped to a readable measure.\n ctx.fillStyle = 'rgba(255,255,255,0.75)';\n ctx.font = `${Math.round(24 * uiF)}px Inter`;\n const maxW = Math.min(1200, width - 200);\n const words = card.message.replace(/\\s+/g, ' ').split(' ');\n const lines: string[] = [];\n let line = '';\n for (const w of words) {\n const probe = line ? `${line} ${w}` : w;\n if (ctx.measureText(probe).width > maxW && line) {\n lines.push(line);\n line = w;\n if (lines.length >= 3) break;\n } else line = probe;\n }\n if (lines.length < 3 && line) lines.push(line);\n else if (line && lines.length >= 3) lines[2] = `${lines[2]!.slice(0, -1)}…`;\n lines.forEach((l, i) => ctx.fillText(l, width / 2, height / 2 + 48 + i * 36));\n ctx.restore();\n}\n\nexport function drawTitleCard(\n ctx: SKRSContext2D,\n card: TitleCardOverlay,\n tOut: number,\n theme: ResolvedTheme,\n profile: OutputProfile,\n): void {\n const { width, height } = profile;\n // Ground with the same gradient the stage uses, so the dip into footage feels continuous.\n const g = ctx.createLinearGradient(0, 0, 0, height);\n g.addColorStop(0, theme.bgSubtle);\n g.addColorStop(1, theme.bg);\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, width, height);\n\n // Staggered entrance: bar → title → subtitle, each rising 16px as it fades in. A group fade\n // with zero motion reads as a slide; a 200ms stagger reads as designed.\n const t = tOut - card.tStart;\n const enter = (delay: number) => {\n const u = clamp((t - delay) / 380, 0, 1);\n const e = 1 - (1 - u) * (1 - u) * (1 - u); // easeOutCubic\n return { alpha: u, rise: 16 * (1 - e) };\n };\n const bar = enter(0);\n const title = enter(130);\n const sub = enter(240);\n\n ctx.save();\n ctx.globalAlpha = bar.alpha;\n ctx.fillStyle = theme.accent;\n roundRect(ctx, width / 2 - 32, height / 2 - 110 + bar.rise, 64, 8, 4);\n ctx.fill();\n\n ctx.globalAlpha = title.alpha;\n ctx.fillStyle = '#ffffff';\n const uiT = profile.uiScale;\n ctx.font = `${Math.round(56 * uiT)}px Inter Bold`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(card.title, width / 2, height / 2 - 20 + title.rise);\n\n if (card.subtitle) {\n ctx.globalAlpha = sub.alpha;\n ctx.fillStyle = theme.onSurfaceDim;\n ctx.font = `${Math.round(26 * uiT)}px Inter`;\n ctx.fillText(card.subtitle, width / 2, height / 2 + 44 + sub.rise);\n }\n ctx.restore();\n}\n","import sharp from 'sharp';\nimport { createCanvas, ImageData, type Canvas } from '@napi-rs/canvas';\nimport type { BundleData } from '../../bundle/types.js';\nimport { frameIndexForTime, framePath } from '../../bundle/reader.js';\n\nconst LRU_SIZE = 6;\n\n/**\n * Timestamp-indexed source-frame store with an LRU of decoded frames and one-ahead\n * prefetch. Access during a render is monotonic in time, so a small cache wins.\n */\nexport class FrameStore {\n private cache = new Map<number, Promise<Canvas>>();\n\n constructor(private readonly bundle: BundleData) {}\n\n /** Decoded canvas for the frame that should be on screen at capture-relative tMs. */\n async frameForTime(tMs: number): Promise<Canvas> {\n const idx = frameIndexForTime(this.bundle.frames, tMs);\n const canvas = await this.get(idx);\n // Prefetch the next distinct frame while this one is being drawn.\n // A rejected prefetch with no handler is process-fatal AND poisons the LRU — attach a\n // silent handler; the entry self-evicts below so the real read retries (round-2 audit).\n if (idx + 1 < this.bundle.frames.length) this.get(idx + 1).catch(() => {});\n return canvas;\n }\n\n /**\n * The frame at tMs plus its successor with a blend factor: the capture is ~20fps but output\n * is 30fps, so nearest-frame playback holds each source frame in a 2-1-2-1 judder pattern.\n * Blending adjacent frames during real motion smooths it without optical flow.\n */\n async framePairForTime(tMs: number): Promise<{ a: Canvas; b: Canvas | null; mix: number; gapMs: number }> {\n const idx = frameIndexForTime(this.bundle.frames, tMs);\n const a = await this.get(idx);\n if (idx + 1 >= this.bundle.frames.length) return { a, b: null, mix: 0, gapMs: Infinity };\n const t0 = this.bundle.frames[idx]!.t;\n const t1 = this.bundle.frames[idx + 1]!.t;\n const gapMs = t1 - t0;\n const mix = gapMs > 0 ? Math.min(1, Math.max(0, (tMs - t0) / gapMs)) : 0;\n const b = await this.get(idx + 1);\n return { a, b, mix, gapMs };\n }\n\n private get(idx: number): Promise<Canvas> {\n const hit = this.cache.get(idx);\n if (hit) {\n // refresh recency\n this.cache.delete(idx);\n this.cache.set(idx, hit);\n return hit;\n }\n const promise = this.decode(idx);\n // Self-evict on failure so a transient decode error (EMFILE under load) doesn't poison\n // the cache — the next read of this index retries instead of re-throwing forever.\n promise.catch(() => this.cache.delete(idx));\n this.cache.set(idx, promise);\n while (this.cache.size > LRU_SIZE) {\n const oldest = this.cache.keys().next().value as number;\n this.cache.delete(oldest);\n }\n return promise;\n }\n\n private async decode(idx: number): Promise<Canvas> {\n const { data, info } = await sharp(framePath(this.bundle, idx))\n .ensureAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true });\n const canvas = createCanvas(info.width, info.height);\n const ctx = canvas.getContext('2d');\n ctx.putImageData(new ImageData(new Uint8ClampedArray(data.buffer, data.byteOffset, data.byteLength), info.width, info.height), 0, 0);\n return canvas;\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\nimport { once } from 'node:events';\nimport { ffmpegPath } from '../../shared/ffmpeg.js';\n\n/**\n * Streaming H.264 encoder: raw RGBA frames in on stdin, MP4 out. Backpressure is\n * respected — write() resolves only when the pipe can take more.\n */\nexport class Encoder {\n private child: ChildProcess;\n private stderrTail: string[] = [];\n private exit: Promise<number>;\n\n constructor(outPath: string, width: number, height: number, fps: number) {\n this.child = spawn(\n ffmpegPath(),\n [\n '-hide_banner',\n '-loglevel', 'error',\n '-f', 'rawvideo',\n '-pix_fmt', 'rgba',\n '-s', `${width}x${height}`,\n '-r', String(fps),\n '-i', 'pipe:0',\n // A silent AAC track: some players/galleries refuse an audio-less MP4.\n '-f', 'lavfi',\n '-i', 'anullsrc=channel_layout=stereo:sample_rate=44100',\n '-c:v', 'libx264',\n '-preset', 'medium',\n '-crf', '18',\n '-pix_fmt', 'yuv420p',\n '-profile:v', 'high',\n '-c:a', 'aac',\n '-b:a', '96k',\n '-shortest',\n '-movflags', '+faststart',\n '-y',\n outPath,\n ],\n { stdio: ['pipe', 'ignore', 'pipe'] },\n );\n this.child.stderr!.on('data', (d: Buffer) => {\n this.stderrTail.push(d.toString('utf8'));\n if (this.stderrTail.length > 40) this.stderrTail.shift();\n });\n this.exit = new Promise((resolve, reject) => {\n this.child.on('error', reject);\n this.child.on('close', (code) => resolve(code ?? -1));\n });\n // Late EPIPEs on stdin (ffmpeg died mid-write) must not become uncaught exceptions.\n this.child.stdin!.on('error', () => {});\n }\n\n async write(rgba: Buffer): Promise<void> {\n const stdin = this.child.stdin!;\n if (!stdin.writable) throw new Error(`ffmpeg closed early: ${this.stderrTail.join('')}`);\n if (!stdin.write(rgba)) {\n // If ffmpeg dies while the pipe is full, 'drain' never fires — race against the exit\n // promise so an eternal hang becomes a diagnosable failure (round-2 audit).\n await Promise.race([\n once(stdin, 'drain'),\n this.exit.then((code) => {\n throw new Error(`ffmpeg exited (code ${code}) while the encoder awaited drain: ${this.stderrTail.join('')}`);\n }),\n ]);\n }\n }\n\n async finish(): Promise<void> {\n this.child.stdin!.end();\n const code = await this.exit;\n if (code !== 0) {\n throw new Error(`ffmpeg exited with code ${code}: ${this.stderrTail.join('')}`);\n }\n }\n}\n","import { spawn } from 'node:child_process';\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\n/** Resolve the ffmpeg binary: $PLAYHEAD_FFMPEG override, else the bundled ffmpeg-static build. */\nexport function ffmpegPath(): string {\n if (process.env.PLAYHEAD_FFMPEG) return process.env.PLAYHEAD_FFMPEG;\n const p = require('ffmpeg-static') as string | null;\n if (!p) throw new Error('ffmpeg-static did not provide a binary; set PLAYHEAD_FFMPEG');\n return p;\n}\n\nexport function ffprobePath(): string {\n if (process.env.PLAYHEAD_FFPROBE) return process.env.PLAYHEAD_FFPROBE;\n const mod = require('ffprobe-static') as { path: string };\n return mod.path;\n}\n\nexport interface RunResult {\n code: number;\n stdout: string;\n stderr: string;\n}\n\n/** Run ffmpeg/ffprobe to completion, capturing output. For the streaming encoder see compose/render/encoder.ts. */\nexport function runBinary(bin: string, args: string[], stdin?: Buffer): Promise<RunResult> {\n return new Promise((resolve, reject) => {\n const child = spawn(bin, args, { stdio: ['pipe', 'pipe', 'pipe'] });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n child.stdout.on('data', (d) => out.push(d));\n child.stderr.on('data', (d) => err.push(d));\n child.on('error', reject);\n child.on('close', (code) => {\n resolve({\n code: code ?? -1,\n stdout: Buffer.concat(out).toString('utf8'),\n stderr: Buffer.concat(err).toString('utf8'),\n });\n });\n if (stdin) child.stdin.end(stdin);\n else child.stdin.end();\n });\n}\n\n/** Losslessly concatenate H.264 MP4s (same codec/params) into one file via the concat demuxer. */\nexport async function concatVideos(inputs: string[], outPath: string): Promise<void> {\n const { writeFile, mkdtemp, rm } = await import('node:fs/promises');\n const { join } = await import('node:path');\n const { tmpdir } = await import('node:os');\n const dir = await mkdtemp(join(tmpdir(), 'playhead-concat-'));\n const listPath = join(dir, 'list.txt');\n await writeFile(listPath, inputs.map((p) => `file '${p.replace(/'/g, \"'\\\\''\")}'`).join('\\n'));\n try {\n const res = await runBinary(ffmpegPath(), [\n '-hide_banner', '-loglevel', 'error',\n '-f', 'concat', '-safe', '0',\n '-i', listPath,\n '-c', 'copy',\n '-movflags', '+faststart',\n '-y', outPath,\n ]);\n if (res.code !== 0) throw new Error(`concat failed: ${res.stderr}`);\n } finally {\n await rm(dir, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/** Run ffmpeg, returning raw stdout bytes (for image2pipe extraction). */\nexport function runBinaryRaw(bin: string, args: string[]): Promise<{ code: number; stdout: Buffer; stderr: string }> {\n return new Promise((resolve, reject) => {\n const child = spawn(bin, args, { stdio: ['ignore', 'pipe', 'pipe'] });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n child.stdout.on('data', (d) => out.push(d));\n child.stderr.on('data', (d) => err.push(d));\n child.on('error', reject);\n child.on('close', (code) => {\n resolve({ code: code ?? -1, stdout: Buffer.concat(out), stderr: Buffer.concat(err).toString('utf8') });\n });\n });\n}\n","import sharp from 'sharp';\nimport { ffmpegPath, ffprobePath, runBinaryRaw, runBinary } from '../shared/ffmpeg.js';\nimport type { BundleData } from '../bundle/types.js';\nimport { frameIndexForTime, framePath } from '../bundle/reader.js';\n\n/** Extract grayscale frames from the output video at a fixed rate. */\nexport async function extractGrayFrames(\n videoPath: string,\n fps: number,\n w: number,\n h: number,\n): Promise<{ frames: Buffer[]; intervalMs: number }> {\n const res = await runBinaryRaw(ffmpegPath(), [\n '-hide_banner', '-loglevel', 'error',\n '-i', videoPath,\n '-vf', `fps=${fps},scale=${w}:${h}`,\n '-f', 'rawvideo',\n '-pix_fmt', 'gray',\n 'pipe:1',\n ]);\n if (res.code !== 0) throw new Error(`frame extraction failed: ${res.stderr}`);\n const frameSize = w * h;\n const frames: Buffer[] = [];\n for (let off = 0; off + frameSize <= res.stdout.length; off += frameSize) {\n frames.push(res.stdout.subarray(off, off + frameSize));\n }\n return { frames, intervalMs: 1000 / fps };\n}\n\n/** Extract one PNG frame from the output video at a timestamp (ms). */\nexport async function extractFrameAt(videoPath: string, tMs: number): Promise<Buffer> {\n const res = await runBinaryRaw(ffmpegPath(), [\n '-hide_banner', '-loglevel', 'error',\n '-ss', (Math.max(0, tMs) / 1000).toFixed(3),\n '-i', videoPath,\n '-frames:v', '1',\n '-f', 'image2pipe',\n '-vcodec', 'png',\n 'pipe:1',\n ]);\n if (res.code !== 0 || res.stdout.length === 0) {\n throw new Error(`could not extract frame at ${tMs}ms: ${res.stderr}`);\n }\n return res.stdout;\n}\n\nexport interface ProbeInfo {\n codec: string;\n width: number;\n height: number;\n durationSec: number;\n fps: number;\n}\n\nexport async function probeVideo(videoPath: string): Promise<ProbeInfo> {\n const res = await runBinary(ffprobePath(), [\n '-v', 'error',\n '-print_format', 'json',\n '-show_format',\n '-show_streams',\n videoPath,\n ]);\n if (res.code !== 0) throw new Error(`ffprobe failed: ${res.stderr}`);\n const json = JSON.parse(res.stdout) as {\n streams?: { codec_type: string; codec_name: string; width: number; height: number; avg_frame_rate: string }[];\n format?: { duration?: string };\n };\n const v = json.streams?.find((s) => s.codec_type === 'video');\n if (!v) throw new Error('no video stream found');\n const [num, den] = v.avg_frame_rate.split('/').map(Number);\n return {\n codec: v.codec_name,\n width: v.width,\n height: v.height,\n durationSec: Number(json.format?.duration ?? 0),\n fps: den ? num! / den : 0,\n };\n}\n\nexport function meanAbsDiff(a: Buffer, b: Buffer): number {\n const n = Math.min(a.length, b.length);\n let sum = 0;\n for (let i = 0; i < n; i++) sum += Math.abs(a[i]! - b[i]!);\n return sum / n;\n}\n\nexport function variance(a: Buffer): number {\n let sum = 0;\n for (let i = 0; i < a.length; i++) sum += a[i]!;\n const mean = sum / a.length;\n let v = 0;\n for (let i = 0; i < a.length; i++) v += (a[i]! - mean) ** 2;\n return v / a.length;\n}\n\n/** Decode a capture-bundle source frame to grayscale at reduced width. */\nexport async function sourceFrameGray(\n bundle: BundleData,\n tMs: number,\n width: number,\n): Promise<{ data: Buffer; w: number; h: number; frameT: number }> {\n const idx = frameIndexForTime(bundle.frames, tMs);\n const { data, info } = await sharp(framePath(bundle, idx))\n .resize({ width })\n .grayscale()\n .raw()\n .toBuffer({ resolveWithObject: true });\n return { data, w: info.width, h: info.height, frameT: bundle.frames[idx]!.t };\n}\n\n/** Decode a region of a source frame (frame px) to grayscale raw. */\nexport async function sourceRegionGray(\n bundle: BundleData,\n tMs: number,\n region: { x: number; y: number; w: number; h: number },\n preferAfter = false,\n color = false,\n): Promise<Buffer | null> {\n let idx = frameIndexForTime(bundle.frames, tMs);\n if (preferAfter && idx + 1 < bundle.frames.length && bundle.frames[idx]!.t < tMs) idx += 1;\n const meta = await sharp(framePath(bundle, idx)).metadata();\n const fw = meta.width ?? 0;\n const fh = meta.height ?? 0;\n const x = Math.max(0, Math.round(region.x));\n const y = Math.max(0, Math.round(region.y));\n const w = Math.min(Math.round(region.w), fw - x);\n const h = Math.min(Math.round(region.h), fh - y);\n if (w < 4 || h < 4) return null;\n // Grayscale by default (cheap); color on request — a pastel hue swap (blue→red badge) is\n // nearly luminance-neutral and INVISIBLE to a grayscale diff.\n let img = sharp(framePath(bundle, idx)).extract({ left: x, top: y, width: w, height: h });\n if (!color) img = img.grayscale();\n const { data } = await img.raw().toBuffer({ resolveWithObject: true });\n return data;\n}\n\n/** Crop a region from PNG bytes (or an image file), grayscale, resize to 48x48 raw. */\nexport async function regionGray48(input: Buffer | string, rect: { x: number; y: number; w: number; h: number }): Promise<Buffer | null> {\n try {\n const img = sharp(input);\n const meta = await img.metadata();\n const W = meta.width ?? 0;\n const H = meta.height ?? 0;\n const left = Math.max(0, Math.round(rect.x));\n const top = Math.max(0, Math.round(rect.y));\n const width = Math.min(W - left, Math.round(rect.w));\n const height = Math.min(H - top, Math.round(rect.h));\n if (width < 8 || height < 8) return null;\n return await sharp(input).extract({ left, top, width, height }).grayscale().resize(48, 48, { fit: 'fill' }).raw().toBuffer();\n } catch {\n return null;\n }\n}\n\n/** Normalized cross-correlation of two equal-length gray buffers, in [-1, 1]. */\nexport function normalizedCorrelation(a: Buffer, b: Buffer): number {\n const n = Math.min(a.length, b.length);\n let ma = 0;\n let mb = 0;\n for (let i = 0; i < n; i++) {\n ma += a[i]!;\n mb += b[i]!;\n }\n ma /= n;\n mb /= n;\n let num = 0;\n let da = 0;\n let db = 0;\n for (let i = 0; i < n; i++) {\n const xa = a[i]! - ma;\n const xb = b[i]! - mb;\n num += xa * xb;\n da += xa * xa;\n db += xb * xb;\n }\n // Two flat regions (zero variance) are \"the same\" for our purposes.\n if (da < 1e-6 || db < 1e-6) return da < 1e-6 && db < 1e-6 ? 1 : 0;\n return num / Math.sqrt(da * db);\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createHash } from 'node:crypto';\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\nconst ffprobePath: string = require('ffprobe-static').path;\nconst exec = promisify(execFile);\n\nexport interface NarrationOptions {\n /** 'say' — macOS built-in (zero deps, Mac-only). 'kokoro' — natural neural voice, offline,\n * cross-platform, via the optional kokoro-js package. */\n provider: 'say' | 'kokoro';\n /** say: a macOS voice name (Samantha). kokoro: a voice id (af_heart, am_michael, …). */\n voice?: string;\n /** say: words per minute. kokoro: playback speed × 100 (100 = 1.0×). */\n rate?: number;\n}\n\nexport interface NarrationLine {\n stepRef: string;\n text: string;\n}\n\nexport interface NarrationClip {\n stepRef: string;\n file: string;\n durationMs: number;\n}\n\n/** A text-to-speech backend: text → an audio file on disk. */\ninterface TtsProvider {\n readonly name: string;\n synth(text: string, outFile: string): Promise<void>;\n}\n\nclass SayProvider implements TtsProvider {\n readonly name = 'say';\n constructor(private voice: string, private rate: number) {}\n async synth(text: string, outFile: string): Promise<void> {\n // Pass the text via a file so em-dashes / quotes / apostrophes survive shell escaping.\n const txt = `${outFile}.txt`;\n await writeFile(txt, text);\n await exec('say', ['-v', this.voice, '-r', String(this.rate), '-f', txt, '-o', outFile]);\n }\n}\n\n/**\n * Kokoro — a natural, offline neural voice (the Kokoro-82M model) via the optional pure-Node\n * `kokoro-js` package. The model (~90MB q8) loads ONCE on the first line and is reused for the\n * rest, so a multi-line narration pays the load cost a single time. Output is WAV.\n *\n * kokoro-js is NOT a hard dependency (it pulls onnxruntime, ~400MB) — it is lazily imported and,\n * if absent, produces an actionable error. On networks that intercept TLS (corporate proxies),\n * set NODE_EXTRA_CA_CERTS so the one-time model download from Hugging Face can verify.\n */\nclass KokoroProvider implements TtsProvider {\n readonly name = 'kokoro';\n private tts: Promise<{ generate: (t: string, o: { voice: string; speed: number }) => Promise<{ save: (p: string) => Promise<void> }> }> | null = null;\n constructor(private voice: string, private speed: number) {}\n\n private load() {\n if (this.tts) return this.tts;\n this.tts = (async () => {\n let mod: { KokoroTTS: { from_pretrained: (id: string, o: object) => Promise<unknown> } };\n try {\n mod = (await import('kokoro-js' as string)) as typeof mod;\n } catch {\n throw new Error(\n \"the 'kokoro' voice needs the optional kokoro-js package — install it with `npm i -g kokoro-js` \" +\n '(or add it to your project). It bundles the neural model runtime (~400MB); the base playhead-cli stays lean.',\n );\n }\n return (await mod.KokoroTTS.from_pretrained('onnx-community/Kokoro-82M-v1.0-ONNX', {\n dtype: 'q8',\n device: 'cpu',\n })) as Awaited<NonNullable<KokoroProvider['tts']>>;\n })();\n return this.tts;\n }\n\n async synth(text: string, outFile: string): Promise<void> {\n const tts = await this.load();\n const audio = await tts.generate(text, { voice: this.voice, speed: this.speed });\n await audio.save(outFile); // WAV\n }\n}\n\nfunction providerFor(opts: NarrationOptions): { provider: TtsProvider; voice: string; rate: number } {\n switch (opts.provider) {\n case 'say': {\n const voice = opts.voice ?? 'Samantha';\n const rate = opts.rate ?? 178;\n return { provider: new SayProvider(voice, rate), voice, rate };\n }\n case 'kokoro': {\n // Two curated voices only — Heart (default) and Michael. Friendly aliases map to the ids.\n const KOKORO_VOICES: Record<string, string> = {\n heart: 'af_heart',\n af_heart: 'af_heart',\n michael: 'am_michael',\n am_michael: 'am_michael',\n };\n const requested = opts.voice ?? 'heart';\n const voice = KOKORO_VOICES[requested];\n if (!voice) throw new Error(`kokoro voice must be 'heart' (default) or 'michael', got '${requested}'`);\n const rate = opts.rate ?? 100; // ×100 → 1.0 playback speed\n return { provider: new KokoroProvider(voice, rate / 100), voice, rate };\n }\n default:\n throw new Error(`unknown TTS provider: ${(opts as { provider: string }).provider}`);\n }\n}\n\nasync function probeDurationMs(file: string): Promise<number> {\n const { stdout } = await exec(ffprobePath, [\n '-v', 'error', '-show_entries', 'format=duration', '-of', 'csv=p=0', file,\n ]);\n return Math.round(parseFloat(stdout.trim()) * 1000);\n}\n\n/**\n * Synthesize one clip per line. Clips are cached by a content hash of\n * (provider, voice, rate, text) so re-renders reuse them — keeping compose offline\n * and deterministic (same text+voice → same audio → same timing).\n */\nexport async function synthesizeNarration(\n lines: NarrationLine[],\n opts: NarrationOptions,\n cacheDir: string,\n): Promise<Map<string, NarrationClip>> {\n await mkdir(cacheDir, { recursive: true });\n const { provider, voice, rate } = providerFor(opts);\n const ext = provider.name === 'kokoro' ? 'wav' : 'aiff';\n const out = new Map<string, NarrationClip>();\n for (const { stepRef, text } of lines) {\n const key = createHash('sha256').update(`${provider.name}|${voice}|${rate}|${text}`).digest('hex').slice(0, 16);\n const file = join(cacheDir, `${key}.${ext}`);\n if (!existsSync(file)) await provider.synth(text, file);\n out.set(stepRef, { stepRef, file, durationMs: await probeDurationMs(file) });\n }\n return out;\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { rename, mkdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createRequire } from 'node:module';\nimport type { StepMapEntry, ClickRipple } from '../compose/types.js';\nimport type { NarrationClip } from './tts.js';\nimport { AUDIO_LEAD_MS } from './timing.js';\n\nconst require = createRequire(import.meta.url);\nconst ffmpegPath: string = require('ffmpeg-static');\nconst exec = promisify(execFile);\n\nexport interface PlacedClip {\n stepRef: string;\n /** Output-clock ms the clip starts playing. */\n tStart: number;\n durMs: number;\n}\n\nexport interface AudioBedOptions {\n /** Narration clips per stepRef (absent = no narration). */\n narration?: Map<string, NarrationClip>;\n /** Click-beat times (output clock) that get a soft synthesized tick. */\n sfxBeats?: ClickRipple[];\n /** Keystroke-tick times (output clock) — quieter, shorter, higher than clicks. */\n keyBeats?: number[];\n /** User-supplied music bed (no asset is bundled). */\n music?: { file: string; gainDb: number };\n /** Directory for the synthesized click sample (cached). */\n cacheDir: string;\n}\n\n/**\n * Build the full audio track — narration clips at their step starts, click ticks at ripple\n * beats, an optional music bed ducked under narration — normalize loudness (EBU R128, I=-16),\n * and mux it onto the rendered MP4. Returns where each narration clip landed so verification\n * can reason about voice windows.\n */\nexport async function mixAudio(\n videoPath: string,\n steps: StepMapEntry[],\n durationMs: number,\n opts: AudioBedOptions,\n): Promise<PlacedClip[]> {\n const placed = (opts.narration ? steps : [])\n .map((s) => ({ start: Math.round(s.outStart + AUDIO_LEAD_MS), clip: opts.narration!.get(s.stepRef) }))\n .filter((p): p is { start: number; clip: NarrationClip } => p.clip !== undefined);\n const beats = opts.sfxBeats ?? [];\n const keyBeats = opts.keyBeats ?? [];\n const hasMusic = !!opts.music;\n if (placed.length === 0 && beats.length === 0 && keyBeats.length === 0 && !hasMusic) return [];\n\n const durSec = (durationMs / 1000).toFixed(3);\n const args = ['-y', '-loglevel', 'error', '-i', videoPath];\n const inputs: string[] = []; // filter labels for the final mix\n const filters: string[] = [];\n let inputIdx = 1;\n\n // Silent full-length base keeps the mix spanning the whole video.\n args.push('-f', 'lavfi', '-t', durSec, '-i', 'anullsrc=r=44100:cl=stereo');\n const baseIdx = inputIdx++;\n inputs.push(`[${baseIdx}]`);\n\n // Narration clips, delayed to their step starts, pre-mixed into one voice bus.\n let voiceBus: string | null = null;\n if (placed.length > 0) {\n const labels: string[] = [];\n placed.forEach((p, i) => {\n args.push('-i', p.clip.file);\n const idx = inputIdx++;\n filters.push(\n `[${idx}]aformat=sample_rates=44100:channel_layouts=stereo,adelay=${p.start}|${p.start}[v${i}]`,\n );\n labels.push(`[v${i}]`);\n });\n filters.push(`${labels.join('')}amix=inputs=${labels.length}:normalize=0:duration=longest[voice]`);\n voiceBus = '[voice]';\n }\n\n // Click SFX: one synthesized sample, split and delayed to each beat.\n if (beats.length > 0) {\n const click = await ensureClickSample(opts.cacheDir);\n args.push('-i', click);\n const idx = inputIdx++;\n const splits = beats.map((_, i) => `[c${i}]`).join('');\n filters.push(`[${idx}]aformat=sample_rates=44100:channel_layouts=stereo,asplit=${beats.length}${splits}`);\n const labels: string[] = [];\n beats.forEach((b, i) => {\n const at = Math.max(0, Math.round(b.tOut));\n filters.push(`[c${i}]adelay=${at}|${at}[ck${i}]`);\n labels.push(`[ck${i}]`);\n });\n filters.push(`${labels.join('')}amix=inputs=${labels.length}:normalize=0:duration=longest[sfx]`);\n inputs.push('[sfx]');\n }\n\n // Keystroke ticks: a much softer, shorter sample scattered through the natural-rate typing\n // windows — the audible half of the typing-cadence craft (the fast-forwarded middle stays\n // silent on purpose: ticking through a 3x speed-up would be absurd).\n if (keyBeats.length > 0) {\n const key = await ensureKeySample(opts.cacheDir);\n args.push('-i', key);\n const idx = inputIdx++;\n const splits = keyBeats.map((_, i) => `[k${i}]`).join('');\n filters.push(`[${idx}]aformat=sample_rates=44100:channel_layouts=stereo,asplit=${keyBeats.length}${splits}`);\n const labels: string[] = [];\n keyBeats.forEach((t, i) => {\n const at = Math.max(0, Math.round(t));\n filters.push(`[k${i}]adelay=${at}|${at}[kk${i}]`);\n labels.push(`[kk${i}]`);\n });\n filters.push(`${labels.join('')}amix=inputs=${labels.length}:normalize=0:duration=longest[keys]`);\n inputs.push('[keys]');\n }\n\n // Music bed: looped to length, faded out, gained down — and DUCKED under narration.\n if (opts.music) {\n args.push('-stream_loop', '-1', '-i', opts.music.file);\n const idx = inputIdx++;\n const fadeStart = Math.max(0, durationMs / 1000 - 1.8).toFixed(2);\n filters.push(\n `[${idx}]aformat=sample_rates=44100:channel_layouts=stereo,atrim=0:${durSec},` +\n `volume=${opts.music.gainDb}dB,afade=t=out:st=${fadeStart}:d=1.8[mraw]`,\n );\n if (voiceBus) {\n // Duplicate the voice bus: one copy keys the compressor, one goes to the mix.\n filters.push(`${voiceBus}asplit=2[vmain][vkey]`);\n filters.push(`[mraw][vkey]sidechaincompress=threshold=0.02:ratio=8:attack=40:release=400[mduck]`);\n inputs.push('[mduck]', '[vmain]');\n voiceBus = null;\n } else {\n inputs.push('[mraw]');\n }\n }\n if (voiceBus) inputs.push(voiceBus);\n\n filters.push(\n `${inputs.join('')}amix=inputs=${inputs.length}:normalize=0:duration=longest,` +\n `loudnorm=I=-16:TP=-1.5:LRA=11[mix]`,\n );\n\n const tmp = videoPath.replace(/\\.mp4$/, '.audio.tmp.mp4');\n args.push(\n '-filter_complex', filters.join(';'),\n '-map', '0:v:0', '-map', '[mix]',\n '-c:v', 'copy', '-c:a', 'aac', '-b:a', '160k',\n '-shortest', '-movflags', '+faststart',\n tmp,\n );\n await exec(ffmpegPath, args, { maxBuffer: 1 << 24 });\n await rename(tmp, videoPath);\n return placed.map((p) => ({ stepRef: p.clip.stepRef, tStart: p.start, durMs: p.clip.durationMs }));\n}\n\n/** Synthesize the click sample once: a soft 2-tone tick with a fast decay (no bundled assets). */\n/** A keystroke tick: shorter, quieter, and higher than the click — felt more than heard. */\nasync function ensureKeySample(cacheDir: string): Promise<string> {\n await mkdir(cacheDir, { recursive: true });\n const file = join(cacheDir, 'key.wav');\n if (existsSync(file)) return file;\n await exec(ffmpegPath, [\n '-y', '-loglevel', 'error',\n '-f', 'lavfi', '-i', 'sine=frequency=3400:duration=0.022',\n '-filter_complex',\n '[0]volume=0.12,afade=t=in:d=0.002,afade=t=out:st=0.008:d=0.014,aformat=sample_rates=44100:channel_layouts=stereo',\n file,\n ]);\n return file;\n}\n\nasync function ensureClickSample(cacheDir: string): Promise<string> {\n await mkdir(cacheDir, { recursive: true });\n const file = join(cacheDir, 'click.wav');\n if (existsSync(file)) return file;\n await exec(ffmpegPath, [\n '-y', '-loglevel', 'error',\n '-f', 'lavfi', '-i', 'sine=frequency=1250:duration=0.05',\n '-f', 'lavfi', '-i', 'sine=frequency=2500:duration=0.03',\n '-filter_complex',\n '[0]volume=0.5[a];[1]volume=0.22[b];[a][b]amix=inputs=2:normalize=0,afade=t=in:d=0.004,afade=t=out:st=0.014:d=0.036,aformat=sample_rates=44100:channel_layouts=stereo',\n file,\n ]);\n return file;\n}\n","import { join } from 'node:path';\nimport { mkdir, writeFile, readFile } from 'node:fs/promises';\nimport type { BundleData } from '../bundle/types.js';\nimport type { ComposeManifest } from '../compose/types.js';\nimport type { CheckResult, Verdict, VerifyContext } from './types.js';\nimport {\n checkActionEffect,\n checkAudio,\n checkCaptions,\n checkCursorOnTarget,\n checkEncode,\n checkFrozenBlank,\n checkMasks,\n checkOutputPixels,\n checkPacing,\n checkTargetInFrame,\n} from './checks.js';\nimport { renderContactSheet } from './contact-sheet.js';\nimport { visionReview } from './vision.js';\nimport { sha256File, sha256Json } from '../bundle/hash.js';\nimport { signVerdict } from './report.js';\nimport { PLAYHEAD_VERSION } from '../shared/version.js';\nimport { log } from '../shared/log.js';\nimport { platform, arch } from 'node:os';\nimport pc from 'picocolors';\n\n/** Bumped whenever a check is added or its semantics change — part of provenance. */\nexport const CHECK_SUITE_VERSION = 'playhead/checks@3';\n\nexport interface VerifyOptions {\n outDir: string;\n vision?: boolean;\n}\n\nexport async function verify(\n bundle: BundleData,\n manifest: ComposeManifest,\n videoPath: string,\n opts: VerifyOptions,\n): Promise<Verdict> {\n const verifyDir = join(opts.outDir, 'verify');\n await mkdir(verifyDir, { recursive: true });\n const ctx: VerifyContext = { bundle, manifest, videoPath, outDir: verifyDir };\n\n log.info('verifying output');\n const checks: CheckResult[] = [];\n const suite = [\n checkEncode, // fail fast on a broken file before decoding frames from it\n checkTargetInFrame,\n checkCursorOnTarget,\n checkActionEffect,\n checkOutputPixels, // the delivered MP4, not the plan\n checkFrozenBlank,\n checkCaptions,\n checkPacing,\n checkMasks,\n checkAudio,\n ];\n for (const check of suite) {\n const result = await check(ctx);\n checks.push(result);\n report(result);\n }\n\n const contactSheet = join(verifyDir, 'contact-sheet.png');\n await renderContactSheet(manifest, videoPath, contactSheet);\n log.ok(`contact sheet → ${contactSheet}`);\n\n let vision: Verdict['vision'] = null;\n if (opts.vision) {\n const { check, review } = await visionReview(contactSheet, manifest);\n checks.push(check);\n report(check);\n vision = review;\n }\n\n const failed = checks.some((c) => c.status === 'fail');\n // Coverage: what was actually pixel-verified, aggregated from the checks that ground\n // themselves in pixels. A verdict where everything skipped now READS differently from a\n // fully verified one — and the numbers are inside the signed payload.\n const effectCoverage = checks.find((c) => c.id === 'action-effect')?.coverage;\n const pixelCoverage = checks.find((c) => c.id === 'output-pixels')?.coverage;\n const coverage: Verdict['coverage'] = {\n actionsVerified: effectCoverage?.verified ?? 0,\n actionsTotal: effectCoverage?.total ?? 0,\n outputSamplesVerified: pixelCoverage?.verified ?? 0,\n checksSkipped: checks.filter((c) => c.status === 'skip').length,\n checksWarned: checks.filter((c) => c.status === 'warn').length,\n };\n\n const unsigned: Omit<Verdict, 'signature'> = {\n schema: 'playhead/verdict@3',\n verdict: failed ? 'not-publishable' : 'publishable',\n // ALWAYS hash the file the checks actually ran against — never trust the manifest's claim\n // (an unauthenticated JSON from disk). Round-2 audit: a doctored manifest could bind the\n // signed verdict to a video that was never verified.\n video: { path: videoPath, sha256: await sha256File(videoPath) },\n bundleHashes: manifest.bundleHashes,\n // The compose manifest is the oracle for the plan-side checks — hash it into the verdict\n // so a doctored manifest can no longer mint passes undetected.\n manifestHash: sha256Json(manifest),\n contactSheetSha256: await sha256File(contactSheet),\n coverage,\n provenance: {\n playheadVersion: PLAYHEAD_VERSION,\n specHash: bundle.manifest.specHash,\n appUrl: bundle.manifest.appUrl,\n capturedAt: bundle.manifest.createdAtIso,\n verifiedAt: new Date().toISOString(),\n checkSuiteVersion: CHECK_SUITE_VERSION,\n host: `${platform()}-${arch()}`,\n ...(bundle.manifest.partial ? { partial: true } : {}),\n ...(bundle.manifest.failure ? { failure: bundle.manifest.failure } : {}),\n },\n checks,\n contactSheet,\n vision,\n };\n const verdict: Verdict = { ...unsigned, signature: signVerdict(unsigned) };\n if (!verdict.signature) log.debug('verdict unsigned — set PLAYHEAD_SIGNING_KEY to sign');\n await writeFile(join(verifyDir, 'verdict.json'), JSON.stringify(verdict, null, 2));\n\n const cov = coverage.actionsTotal > 0 ? ` (coverage: ${coverage.actionsVerified}/${coverage.actionsTotal} actions pixel-verified, ${coverage.outputSamplesVerified} output samples)` : ' (coverage: no effectful actions)';\n if (failed) log.error(`verdict: NOT PUBLISHABLE${cov}`);\n else log.ok(`verdict: publishable${cov}`);\n return verdict;\n}\n\n/** Re-load a compose manifest from disk (for `playhead verify <bundle> <mp4>`). */\nexport async function loadComposeManifest(path: string): Promise<ComposeManifest> {\n const manifest = JSON.parse(await readFile(path, 'utf8')) as ComposeManifest;\n if (manifest.schema !== 'playhead/compose@1') {\n throw new Error(`Unsupported compose manifest schema in ${path}`);\n }\n return manifest;\n}\n\nfunction report(c: CheckResult): void {\n const label =\n c.status === 'pass'\n ? pc.green('pass')\n : c.status === 'fail'\n ? pc.red('FAIL')\n : c.status === 'warn'\n ? pc.yellow('warn')\n : pc.dim('skip');\n console.error(` ${label} ${c.id}: ${c.details}`);\n for (const e of c.evidence ?? []) {\n console.error(pc.dim(` ${e.stepRef ?? ''}${e.t !== undefined ? ` @${(e.t / 1000).toFixed(1)}s` : ''} — ${e.note}`));\n }\n}\n","import type { VerifyContext, CheckResult, CheckEvidence } from './types.js';\nimport { stageContent, actReactWindows } from '../compose/types.js';\nimport { sampleCamera } from '../compose/camera/interpolate.js';\nimport { sampleCursor, type CursorPlan } from '../compose/cursor/path.js';\nimport { segmentAt, sampleSource, outTimeForSrc } from '../compose/timeline/pacing.js';\nimport { actionEvents } from '../capture/events.js';\nimport { projectRect, rectContains, type CameraPlane, type Rect } from '../shared/geometry.js';\nimport {\n extractFrameAt,\n extractGrayFrames,\n meanAbsDiff,\n normalizedCorrelation,\n probeVideo,\n regionGray48,\n sourceFrameGray,\n sourceRegionGray,\n variance,\n} from './media.js';\nimport { framePath, frameIndexForTime } from '../bundle/reader.js';\nimport { ffmpegPath, ffprobePath, runBinary } from '../shared/ffmpeg.js';\n\nconst EFFECT_KINDS = new Set(['click', 'dblclick', 'type', 'select', 'goto']);\nconst CLICK_KINDS = new Set(['click', 'dblclick', 'select']);\n\n/** The camera projects into STAGE-CONTENT space (same space the planner and renderer use). */\nfunction plane(ctx: VerifyContext): CameraPlane {\n const content = stageContent(ctx.manifest.profile);\n return {\n vpW: ctx.manifest.viewport.w,\n vpH: ctx.manifest.viewport.h,\n outW: content.w,\n outH: content.h,\n };\n}\n\n/** 1. Every target legibly in frame around its action beat. */\nexport async function checkTargetInFrame(ctx: VerifyContext): Promise<CheckResult> {\n const p = plane(ctx);\n const frame: Rect = { x: 0, y: 0, w: p.outW, h: p.outH };\n const evidence: CheckEvidence[] = [];\n let checked = 0;\n let minHeight = Infinity;\n\n // Captions that are visible during a step's hold — the target must not hide behind them.\n const captions = ctx.manifest.overlays.filter((o) => o.kind === 'caption');\n for (const step of ctx.manifest.steps) {\n // The framing promise mirrors the planner exactly (same shared helper): an act→react step\n // promises the action target around the beat and the focused payoff during the settled\n // hold; otherwise the focused rect (or target) across the whole hold. The camera's travel\n // between act and react windows is unchecked by design.\n const handoff = actReactWindows(step);\n const rect = step.focusRectVp ?? step.targetRectVp;\n const windows = handoff\n ? [handoff.act, handoff.react]\n : rect\n ? [{ rect, from: Math.max(step.outStart, step.outBeat - 60), to: step.outEnd }]\n : [];\n if (windows.length === 0) continue;\n checked += 1;\n for (const w of windows)\n for (let t = w.from; t <= w.to; t += 100) {\n const rect = w.rect;\n const cam = sampleCamera(ctx.manifest.camera, t);\n const proj = projectRect(rect, cam, p);\n minHeight = Math.min(minHeight, proj.h);\n if (!rectContains(frame, proj, 2)) {\n evidence.push({ stepRef: step.stepRef, t, note: `target cropped by frame edge (projected ${fmtRect(proj)})` });\n break;\n }\n // A scroll's anchor element is just where we scrolled to — the viewer watches the list\n // move, not that element, so it need only be in frame, not meet the legibility floor.\n // Same for an explicit `focus: wide`: the author chose context over close-up, so the\n // target must be visible but is exempt from the close-up legibility floor.\n if (step.kind !== 'scroll' && step.focus !== 'wide' && proj.h < 28) {\n evidence.push({ stepRef: step.stepRef, t, note: `target renders too small (${proj.h.toFixed(0)}px high)` });\n break;\n }\n // Captions live in FRAME space; the projection is in stage-content space — translate\n // before comparing (the stage origin is (0,0) when no stage is set).\n const content = stageContent(ctx.manifest.profile);\n const projFrame: Rect = { x: proj.x + content.x, y: proj.y + content.y, w: proj.w, h: proj.h };\n const cap = captions.find((c) => t >= c.tStart + 150 && t <= c.tEnd - 150 && rectsOverlap(c.box, projFrame));\n if (cap) {\n evidence.push({ stepRef: step.stepRef, t, note: `caption \"${cap.text}\" overlaps the target` });\n break;\n }\n }\n }\n if (checked === 0) return { id: 'target-in-frame', status: 'skip', details: 'no steps with targets' };\n return evidence.length > 0\n ? { id: 'target-in-frame', status: 'fail', details: `${evidence.length}/${checked} targets violate framing`, evidence }\n : {\n id: 'target-in-frame',\n status: 'pass',\n details: `${checked}/${checked} targets fully framed, min rendered height ${minHeight === Infinity ? '—' : minHeight.toFixed(0) + 'px'}`,\n };\n}\n\n/** 2. Rendered cursor sits on the target at each click beat. */\nexport async function checkCursorOnTarget(ctx: VerifyContext): Promise<CheckResult> {\n const cursorPlan: CursorPlan = {\n segments: ctx.manifest.cursor,\n ripples: ctx.manifest.ripples,\n restStart: { x: ctx.manifest.viewport.w / 2, y: ctx.manifest.viewport.h * 0.6 },\n };\n const evidence: CheckEvidence[] = [];\n let checked = 0;\n for (const step of ctx.manifest.steps) {\n if (!CLICK_KINDS.has(step.kind) || !step.targetRectVp) continue;\n checked += 1;\n const pos = sampleCursor(cursorPlan, step.outBeat);\n const r = step.targetRectVp;\n const pad = 4;\n const inside =\n pos.x >= r.x - pad && pos.x <= r.x + r.w + pad && pos.y >= r.y - pad && pos.y <= r.y + r.h + pad;\n if (!inside) {\n evidence.push({\n stepRef: step.stepRef,\n t: step.outBeat,\n note: `cursor at (${pos.x.toFixed(0)},${pos.y.toFixed(0)}) missed target ${fmtRect(r)}`,\n });\n }\n }\n if (checked === 0) return { id: 'cursor-on-target', status: 'skip', details: 'no click steps' };\n if (evidence.length > 0)\n return { id: 'cursor-on-target', status: 'fail', details: `${evidence.length}/${checked} clicks miss their target`, evidence };\n\n // RENDERED-PIXEL proof: the position math above samples the PLAN. Prove a cursor sprite\n // exists on film: at a click beat, the output pixels around the cursor point must differ\n // from the SAME region of the source bundle frame — which has no cursor by construction\n // (headless capture, cursor re-synthesized at compose). Round-2 audit: a renderer that\n // draws no cursor at all previously passed.\n const p = plane(ctx);\n const content = stageContent(ctx.manifest.profile);\n const frameScale = ctx.bundle.manifest.frameW / ctx.manifest.viewport.w;\n const clickSteps = ctx.manifest.steps.filter((s) => CLICK_KINDS.has(s.kind) && s.targetRectVp);\n let sampled = 0;\n let present = 0;\n for (const step of clickSteps.slice(0, 2)) {\n const t = step.outBeat;\n const pos = sampleCursor(cursorPlan, t);\n const boxVp: Rect = { x: pos.x - 16, y: pos.y - 16, w: 32, h: 32 };\n const cam = sampleCamera(ctx.manifest.camera, t);\n const proj = projectRect(boxVp, cam, p);\n const projFrame: Rect = { x: proj.x + content.x, y: proj.y + content.y, w: proj.w, h: proj.h };\n const { srcAt } = sampleSource(ctx.manifest.segments, t);\n if (srcAt === null) continue;\n const outPng = await extractFrameAt(ctx.videoPath, t).catch(() => null);\n if (!outPng) continue;\n const [outRegion, srcRegion] = await Promise.all([\n regionGray48(outPng, projFrame),\n regionGray48(framePath(ctx.bundle, frameIndexForTime(ctx.bundle.frames, srcAt)), {\n x: boxVp.x * frameScale,\n y: boxVp.y * frameScale,\n w: boxVp.w * frameScale,\n h: boxVp.h * frameScale,\n }),\n ]);\n if (!outRegion || !srcRegion) continue;\n sampled += 1;\n // The sprite (dark arrow, white outline, ~22px) dominates a 32px box — a large diff.\n if (meanAbsDiff(outRegion, srcRegion) > 6) present += 1;\n }\n if (sampled > 0 && present === 0) {\n return {\n id: 'cursor-on-target',\n status: 'fail',\n details: `cursor sprite NOT FOUND in the output pixels at ${sampled} sampled click beat(s) — the plan says it's there, the film disagrees`,\n };\n }\n const renderedNote = sampled > 0 ? `; sprite verified on film at ${present}/${sampled} sampled beat(s)` : '';\n return { id: 'cursor-on-target', status: 'pass', details: `${checked}/${checked} clicks land on target${renderedNote}` };\n}\n\n/** 3. Every action visibly changed the UI (dead-click detection). */\nexport async function checkActionEffect(ctx: VerifyContext): Promise<CheckResult> {\n const evidence: CheckEvidence[] = [];\n const inconclusive: CheckEvidence[] = [];\n let checked = 0;\n const frameScale = ctx.bundle.manifest.frameW / ctx.manifest.viewport.w;\n\n const lastFrameT = ctx.bundle.frames[ctx.bundle.frames.length - 1]!.t;\n const steps = ctx.manifest.steps;\n let skippedMasked = 0;\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]!;\n if (!EFFECT_KINDS.has(step.kind)) continue;\n // A masked field intentionally hides its own change — its effect is unverifiable by design.\n if (step.masked) {\n skippedMasked += 1;\n continue;\n }\n checked += 1;\n // Sample the \"after\" state at this step's settled hold, just before the next action — for an\n // instant hash-route navigation the settle timestamp itself can precede the first post-nav\n // frame, so compare against the fully-settled view instead.\n const nextAction = i + 1 < steps.length ? steps[i + 1]!.srcAction : lastFrameT;\n const afterT = Math.max(step.srcSettled, nextAction - 60);\n const before = await sourceFrameGray(ctx.bundle, step.srcAction - 40, 320);\n const after = await sourceFrameGray(ctx.bundle, afterT, 320);\n if (after.frameT <= before.frameT) {\n // No distinct post-action frame was captured (a capture-loop gap, e.g. under CPU load).\n // Absence of frames can't prove absence of effect, so this is inconclusive, not a failure.\n inconclusive.push({ stepRef: step.stepRef, note: 'no post-action frame captured to compare' });\n continue;\n }\n if (before.frameT >= step.srcAction) {\n // The \"before\" sample clamped to a frame AT/AFTER the action (no pre-action footage —\n // e.g. the first grabs stalled during initial load). Comparing post to post proves\n // nothing either way.\n inconclusive.push({ stepRef: step.stepRef, note: 'no pre-action frame captured to compare' });\n continue;\n }\n const overall = meanAbsDiff(before.data, after.data);\n let regionDiff = 0;\n // Measure where the effect is EXPECTED: the action target, and — for act→react steps —\n // the focused payoff (changing a select recolors the badge ELSEWHERE; the payoff region\n // is where the change actually lands). Take the strongest signal.\n const regions = [step.targetRectVp, step.focusRectVp].filter((r): r is Rect => !!r);\n for (const r of regions) {\n const region = scaleRect(r, frameScale);\n const [ra, rb] = await Promise.all([\n sourceRegionGray(ctx.bundle, step.srcAction - 40, region, false, true),\n sourceRegionGray(ctx.bundle, afterT, region, true, true),\n ]);\n if (ra && rb && ra.length === rb.length) regionDiff = Math.max(regionDiff, meanAbsDiff(ra, rb));\n }\n // Typing changes only a few pixels page-wide, so the local target region is the real signal.\n if (overall < 0.5 && regionDiff < 2) {\n evidence.push({\n stepRef: step.stepRef,\n t: step.outBeat,\n note: `no visible effect (frame diff ${overall.toFixed(2)}, target diff ${regionDiff.toFixed(2)})`,\n });\n }\n }\n if (checked === 0) {\n return {\n id: 'action-effect',\n status: 'skip',\n details: skippedMasked > 0 ? `no verifiable actions (${skippedMasked} masked)` : 'no effectful actions',\n };\n }\n const maskedNote = skippedMasked > 0 ? ` (${skippedMasked} masked skipped)` : '';\n const inconcNote = inconclusive.length > 0 ? `, ${inconclusive.length} inconclusive (capture gap)` : '';\n // Coverage: actions whose effect was actually proven by pixels (not failed, not inconclusive).\n const coverage = { verified: checked - evidence.length - inconclusive.length, total: checked + skippedMasked };\n if (evidence.length > 0) {\n return {\n id: 'action-effect',\n status: 'fail',\n details: `${evidence.length}/${checked} actions show no visible effect${maskedNote}${inconcNote}`,\n evidence: [...evidence, ...inconclusive],\n coverage,\n };\n }\n if (inconclusive.length > 0) {\n return {\n id: 'action-effect',\n status: 'warn',\n details: `${checked - inconclusive.length}/${checked} actions visibly effective; ${inconclusive.length} unverified (capture gap)${maskedNote}`,\n evidence: inconclusive,\n coverage,\n };\n }\n return { id: 'action-effect', status: 'pass', details: `${checked}/${checked} actions visibly effective${maskedNote}`, coverage };\n}\n\n/** 4. No unplanned frozen footage, no blank frames, in the delivered video. */\nexport async function checkFrozenBlank(ctx: VerifyContext): Promise<CheckResult> {\n const { frames, intervalMs } = await extractGrayFrames(ctx.videoPath, 2, 320, 180);\n if (frames.length < 2) return { id: 'frozen-blank', status: 'fail', details: 'could not decode output frames' };\n const evidence: CheckEvidence[] = [];\n\n // Intentional near-uniform frames: title cards, and the dip-to-background fades around them\n // (which momentarily paint mostly theme background). These are design, not dead footage.\n const dips = ctx.manifest.overlays.filter((o) => o.kind === 'dip');\n const inTransition = (t: number) =>\n segmentAt(ctx.manifest.segments, t).kind === 'card' || dips.some((d) => t >= d.tStart - 60 && t <= d.tEnd + 60);\n\n // Blank frames — and blank CONTENT regions. A page mid-hydration paints its shell (header,\n // footer) around an empty main area: the whole-frame variance passes while the part the video\n // exists to show is a void. The center region is where content lives, so a near-uniform center\n // on a live frame is worth a warning (not a fail — some designs legitimately breathe).\n const centerBlank: CheckEvidence[] = [];\n const W = 320;\n const H = 180;\n for (let i = 0; i < frames.length; i++) {\n const t = i * intervalMs;\n if (inTransition(t)) continue;\n if (variance(frames[i]!) < 2) {\n evidence.push({ t, note: `blank frame at ${(t / 1000).toFixed(1)}s` });\n continue;\n }\n const f = frames[i]!;\n const center: number[] = [];\n for (let y = Math.floor(H * 0.3); y < Math.floor(H * 0.7); y++) {\n for (let x = Math.floor(W * 0.25); x < Math.floor(W * 0.75); x++) center.push(f[y * W + x]!);\n }\n if (variance(Buffer.from(center)) < 3) {\n centerBlank.push({ t, note: `content region blank at ${(t / 1000).toFixed(1)}s — still loading? Add a wait: { for: … } step so hydration never gets filmed` });\n }\n }\n\n // Frozen runs: identical stretches that cross more than one step beat, or absurdly long.\n // A masked step is intentionally static on screen (the overlay hides the typing), so its\n // window is legitimately \"frozen\" — exclude it, as action-effect does.\n const maskedWindows = ctx.manifest.steps\n .filter((s) => s.masked)\n .map((s) => ({ start: s.outStart, end: s.outEnd }));\n const inMaskedWindow = (t0: number, t1: number) =>\n maskedWindows.some((w) => t1 >= w.start - 200 && t0 <= w.end + 200);\n\n // The final section (last action through the outro) is an intended hold on the result — a\n // walkthrough often ends held on its final state — so static footage there is not a stall.\n const lastBeat = ctx.manifest.steps.reduce((m, s) => Math.max(m, s.outBeat), 0);\n\n // A narrated video legitimately holds on a static screen WHILE ITS SPOKEN LINE PLAYS — the\n // voice carries it. But that must never blanket-disable stall detection: a frozen run is only\n // exempt when a narration clip actually covers it. (Manifests from before clip windows were\n // recorded fall back to the blanket exemption rather than mis-failing old renders.)\n const narrated = !!ctx.manifest.audio?.narrated;\n const clipWindows = (ctx.manifest.audio?.clips ?? []).map((c) => ({\n start: c.tStart - 300,\n end: c.tStart + c.durMs + 1200, // clip + the tail-and-extend hold pacing grants it\n }));\n const voiceCovers = (t0: number, t1: number) =>\n clipWindows.length === 0\n ? narrated // legacy manifests: no window data — keep the old blanket behavior\n : clipWindows.some((w) => t0 >= w.start && t1 <= w.end);\n\n let runStart = 0;\n for (let i = 1; i <= frames.length; i++) {\n const identical = i < frames.length && meanAbsDiff(frames[i]!, frames[i - 1]!) < 0.15;\n if (!identical) {\n const runMs = (i - 1 - runStart) * intervalMs;\n const t0 = runStart * intervalMs;\n const t1 = (i - 1) * intervalMs;\n const inFinalHold = t0 >= lastBeat - 800;\n if (runMs > 2000 && !inMaskedWindow(t0, t1) && !inFinalHold && !(narrated && voiceCovers(t0, t1))) {\n const beatsInside = ctx.manifest.steps.filter((s) => s.outBeat > t0 + 200 && s.outBeat < t1 - 200);\n if (beatsInside.length >= 1 && runMs > 2500) {\n evidence.push({\n t: t0,\n note: `frozen footage ${(runMs / 1000).toFixed(1)}s spanning ${beatsInside.length} action beat(s)`,\n });\n } else if (runMs > 8000) {\n evidence.push({ t: t0, note: `frozen footage for ${(runMs / 1000).toFixed(1)}s` });\n }\n }\n runStart = i;\n }\n }\n if (evidence.length > 0) {\n return { id: 'frozen-blank', status: 'fail', details: `${evidence.length} frozen/blank issue(s)`, evidence: [...evidence, ...centerBlank] };\n }\n if (centerBlank.length > 0) {\n return {\n id: 'frozen-blank',\n status: 'warn',\n details: `frames live, but ${centerBlank.length} sampled frame(s) have a blank content region (mid-hydration footage?)`,\n evidence: centerBlank,\n };\n }\n return { id: 'frozen-blank', status: 'pass', details: `${frames.length} sampled output frames live and non-blank` };\n}\n\n/** 5. Captions legible: no truncation, font floor respected, inside safe bounds. */\nexport async function checkCaptions(ctx: VerifyContext): Promise<CheckResult> {\n const evidence: CheckEvidence[] = [];\n let warned = 0;\n let count = 0;\n const out: Rect = { x: 0, y: 0, w: ctx.manifest.profile.width, h: ctx.manifest.profile.height };\n for (const o of ctx.manifest.overlays) {\n if (o.kind !== 'caption') continue;\n count += 1;\n if (o.truncated) evidence.push({ stepRef: o.stepRef, note: `caption truncated: \"${o.text}\"` });\n // The overlay's fontPx is uiScale-scaled at build time — compare against the scaled floor.\n if (o.fontPx < Math.round(ctx.manifest.theme.captionMinFontPx * ctx.manifest.profile.uiScale))\n evidence.push({ stepRef: o.stepRef, note: `caption font ${o.fontPx}px below minimum` });\n if (!rectContains(out, o.box, 24)) evidence.push({ stepRef: o.stepRef, note: 'caption box outside safe bounds' });\n if (o.shrunk && !o.truncated) warned += 1;\n }\n if (count === 0) return { id: 'captions', status: 'skip', details: 'no captions' };\n if (evidence.length > 0)\n return { id: 'captions', status: 'fail', details: `${evidence.length} caption problem(s)`, evidence };\n\n // RENDERED-PIXEL proof: the plan-side checks above can't tell whether the renderer actually\n // DREW anything (round-2 audit: a compositor that draws no captions shipped a passing video).\n // Sample up to 3 captions: the box region mid-caption must differ from the same region at a\n // caption-free moment. Fail only when every comparable sample shows nothing drawn.\n const caps = ctx.manifest.overlays.filter((o) => o.kind === 'caption');\n const stride = Math.max(1, Math.floor(caps.length / 3));\n let sampled = 0;\n let drawn = 0;\n for (let i = 0; i < caps.length && sampled < 3; i += stride) {\n const c = caps[i]!;\n const tOn = (c.tStart + c.tEnd) / 2;\n // A caption-free instant for the same box: after this card fades, before the next appears.\n const tOff = c.tEnd + 500;\n const clashes = caps.some((o) => o !== c && tOff >= o.tStart - 100 && tOff <= o.tEnd + 100);\n if (clashes || tOff >= ctx.manifest.durationMs - 200) continue;\n const [onPng, offPng] = await Promise.all([\n extractFrameAt(ctx.videoPath, tOn).catch(() => null),\n extractFrameAt(ctx.videoPath, tOff).catch(() => null),\n ]);\n if (!onPng || !offPng) continue;\n const [ra, rb] = await Promise.all([regionGray48(onPng, c.box), regionGray48(offPng, c.box)]);\n if (!ra || !rb) continue;\n sampled += 1;\n if (meanAbsDiff(ra, rb) > 4) drawn += 1;\n }\n if (sampled > 0 && drawn === 0) {\n return {\n id: 'captions',\n status: 'fail',\n details: `captions planned but NOT FOUND in the output pixels (${sampled} sampled boxes identical with and without caption)`,\n };\n }\n const renderedNote = sampled > 0 ? `; ${drawn}/${sampled} sampled on film` : '';\n return warned > 0\n ? { id: 'captions', status: 'warn', details: `${count} captions ok, ${warned} auto-shrunk to fit${renderedNote}` }\n : { id: 'captions', status: 'pass', details: `${count} captions fit at full size${renderedNote}` };\n}\n\n/** 6. Pacing sanity: steps get readable screen time; total duration sane. */\nexport async function checkPacing(ctx: VerifyContext): Promise<CheckResult> {\n const evidence: CheckEvidence[] = [];\n for (const step of ctx.manifest.steps) {\n const dur = step.outEnd - step.outStart;\n if (step.kind !== 'wait' && dur < 1200) {\n evidence.push({ stepRef: step.stepRef, note: `step on screen only ${(dur / 1000).toFixed(1)}s` });\n }\n }\n const total = ctx.manifest.durationMs;\n if (total < 3000) evidence.push({ note: `video too short (${(total / 1000).toFixed(1)}s)` });\n if (total > 15 * 60_000) evidence.push({ note: `video too long (${(total / 60000).toFixed(1)}min)` });\n return evidence.length > 0\n ? { id: 'pacing', status: 'fail', details: `${evidence.length} pacing violation(s)`, evidence }\n : { id: 'pacing', status: 'pass', details: `${ctx.manifest.steps.length} steps paced ≥1.2s, total ${(total / 1000).toFixed(1)}s` };\n}\n\n/** 7. The MP4 itself is intact and matches the manifest. */\n/** 9. Narration audio: when the video was narrated, the track must exist, be audible, and span the video. */\nexport async function checkAudio(ctx: VerifyContext): Promise<CheckResult> {\n // A degraded render (spec asked for narration, TTS failed) is a QUALITY FAILURE — the video\n // does not deliver what the spec promised, and CI must not ship it as publishable.\n if (ctx.manifest.audio?.degraded) {\n return {\n id: 'audio',\n status: 'fail',\n details: `narration was requested but degraded to silence: ${ctx.manifest.audio.degraded}`,\n };\n }\n // Silent is the DEFAULT and usually the right one — but say how to opt in, here at the one\n // line every silent render passes through, or the feature is undiscoverable.\n if (!ctx.manifest.audio?.narrated) {\n return {\n id: 'audio',\n status: 'skip',\n details: 'no narration — for a voice-over, set output.audio: { narration: tts } and re-compose',\n };\n }\n const evidence: CheckEvidence[] = [];\n\n const probe = await runBinary(ffprobePath(), [\n '-v', 'error', '-select_streams', 'a', '-show_entries', 'stream=codec_name,duration', '-of', 'json', ctx.videoPath,\n ]);\n const stream = (JSON.parse(probe.stdout) as { streams?: { codec_name: string; duration?: string }[] }).streams?.[0];\n if (!stream) return { id: 'audio', status: 'fail', details: 'narration requested but the output has no audio stream' };\n\n // Non-silent? volumedetect reports mean/peak levels on stderr.\n const vd = await runBinary(ffmpegPath(), ['-hide_banner', '-nostats', '-i', ctx.videoPath, '-af', 'volumedetect', '-f', 'null', '-']);\n const mean = Number(/mean_volume:\\s*(-?[\\d.]+) dB/.exec(vd.stderr)?.[1] ?? '0');\n if (mean <= -70) evidence.push({ note: `narration track is effectively silent (mean ${mean} dB)` });\n\n const expectSec = ctx.manifest.durationMs / 1000;\n const aDur = Number(stream.duration ?? 0);\n if (aDur > 0 && Math.abs(aDur - expectSec) > Math.max(0.5, expectSec * 0.05))\n evidence.push({ note: `audio ${aDur.toFixed(1)}s vs video ${expectSec.toFixed(1)}s` });\n\n // A/V SYNC: every narration clip must be AUDIBLE inside its own window. Pacing predicts and\n // mux places independently — a drift bug would otherwise ship a voice describing the\n // previous screen with a passing verdict.\n const clips = ctx.manifest.audio.clips ?? [];\n let loudness: number | null = null;\n if (clips.length > 0) {\n const det = await runBinary(ffmpegPath(), [\n '-hide_banner', '-nostats',\n '-i', ctx.videoPath,\n '-af', 'silencedetect=noise=-40dB:d=0.35,ebur128',\n '-f', 'null', '-',\n ]);\n const silences: { start: number; end: number }[] = [];\n let open: number | null = null;\n for (const m of det.stderr.matchAll(/silence_(start|end): ([\\d.]+)/g)) {\n if (m[1] === 'start') open = parseFloat(m[2]!) * 1000;\n else if (open !== null) {\n silences.push({ start: open, end: parseFloat(m[2]!) * 1000 });\n open = null;\n }\n }\n if (open !== null) silences.push({ start: open, end: ctx.manifest.durationMs });\n for (const clip of clips) {\n const w0 = clip.tStart;\n const w1 = clip.tStart + clip.durMs;\n let silent = 0;\n for (const s of silences) {\n silent += Math.max(0, Math.min(w1, s.end) - Math.max(w0, s.start));\n }\n const voiced = (w1 - w0 - silent) / Math.max(1, w1 - w0);\n if (voiced < 0.45) {\n evidence.push({\n stepRef: clip.stepRef,\n t: clip.tStart,\n note: `narration line is mostly silent in its own window (${(voiced * 100).toFixed(0)}% voiced) — audio/video drift`,\n });\n }\n }\n // Loudness: the mix normalizes to I=-16 LUFS; a big miss means the loudnorm stage broke.\n // ebur128 prints PERIODIC \"I:\" readouts (starting at -70 before audio plays) and a final\n // summary — the integrated value is the LAST match, never the first.\n const lus = [...det.stderr.matchAll(/I:\\s+(-?[\\d.]+)\\s+LUFS/g)];\n const lu = lus[lus.length - 1];\n if (lu) {\n loudness = parseFloat(lu[1]!);\n if (loudness < -20 || loudness > -12) {\n evidence.push({ note: `integrated loudness ${loudness.toFixed(1)} LUFS is outside the -16±4 target` });\n }\n }\n }\n\n return evidence.length\n ? { id: 'audio', status: 'fail', details: `${evidence.length} narration problem(s)`, evidence }\n : {\n id: 'audio',\n status: 'pass',\n details: `${ctx.manifest.audio.lines} lines audible in their windows, ${stream.codec_name}${loudness !== null ? `, ${loudness.toFixed(1)} LUFS` : `, mean ${mean.toFixed(0)} dB`}`,\n };\n}\n\nexport async function checkEncode(ctx: VerifyContext): Promise<CheckResult> {\n let info;\n try {\n info = await probeVideo(ctx.videoPath);\n } catch (e) {\n return { id: 'encode', status: 'fail', details: `unreadable video: ${(e as Error).message}` };\n }\n const problems: string[] = [];\n if (info.codec !== 'h264') problems.push(`codec ${info.codec}`);\n if (info.width !== ctx.manifest.profile.width || info.height !== ctx.manifest.profile.height)\n problems.push(`resolution ${info.width}x${info.height}`);\n const expectSec = ctx.manifest.durationMs / 1000;\n if (Math.abs(info.durationSec - expectSec) > Math.max(0.5, expectSec * 0.03))\n problems.push(`duration ${info.durationSec.toFixed(1)}s vs planned ${expectSec.toFixed(1)}s`);\n if (Math.abs(info.fps - ctx.manifest.profile.fps) > 0.5) problems.push(`fps ${info.fps.toFixed(2)}`);\n return problems.length > 0\n ? { id: 'encode', status: 'fail', details: problems.join('; ') }\n : {\n id: 'encode',\n status: 'pass',\n details: `h264 ${info.width}x${info.height} @ ${info.fps.toFixed(0)}fps, ${info.durationSec.toFixed(1)}s`,\n };\n}\n\n/** 8. Masking held: masked regions are covered in footage, secrets absent from the log. */\nexport async function checkMasks(ctx: VerifyContext): Promise<CheckResult> {\n const evidence: CheckEvidence[] = [];\n const frameScale = ctx.bundle.manifest.frameW / ctx.manifest.viewport.w;\n\n // A mask region can be legitimately occluded by later UI (a dialog opening over a banner),\n // which raises its variance without exposing the sensitive pixels. So group samples by\n // position and require that each masked element reads as covered in its BEST sample —\n // if masking failed entirely, no sample of that element would ever be uniform.\n const buckets = new Map<string, { rect: { x: number; y: number; w: number; h: number }; minSd: number; t: number }>();\n const blurKeys = new Set<string>();\n for (const sample of ctx.bundle.maskSamples) {\n for (const rect of sample.rects) {\n const posKey = `${Math.round(rect.x / 24)}:${Math.round(rect.y / 24)}:${Math.round(rect.w / 24)}:${Math.round(rect.h / 24)}`;\n if (rect.style === 'blur') {\n blurKeys.add(posKey);\n continue; // a blurred region has no reference to compare against; leave it to --vision\n }\n const inset = scaleRect(shrinkRect(rect, Math.min(6, rect.w / 8, rect.h / 8)), frameScale);\n const region = await sourceRegionGray(ctx.bundle, sample.t + 60, inset, true);\n if (!region) continue;\n const sd = Math.sqrt(variance(region));\n const key = posKey;\n const prev = buckets.get(key);\n if (!prev || sd < prev.minSd) buckets.set(key, { rect, minSd: sd, t: sample.t });\n }\n }\n for (const b of buckets.values()) {\n if (b.minSd > 16) {\n evidence.push({ t: b.t, note: `solid mask at ${fmtRect(b.rect)} never verified opaque (best σ=${b.minSd.toFixed(1)})` });\n }\n }\n\n for (const e of actionEvents(ctx.bundle.events)) {\n if (e.masked && e.typedText && /[^•]/.test(e.typedText)) {\n evidence.push({ stepRef: `${e.sceneId}/${e.stepIndex}`, note: 'masked step leaked typed text into the event log' });\n }\n }\n\n if (ctx.bundle.maskSamples.length === 0) {\n return { id: 'masks', status: 'skip', details: 'no masking rules' };\n }\n if (evidence.length > 0) {\n return { id: 'masks', status: 'fail', details: `${evidence.length} mask violation(s)`, evidence };\n }\n\n // OUTPUT-SIDE proof (deferred from R1): the checks above sample SOURCE frames — nothing\n // guaranteed the delivered MP4 keeps the region covered (a renderer bug could re-expose it).\n // Project up to 3 solid-mask samples through the timeline+camera and require low variance\n // in the output pixels too.\n const p = plane(ctx);\n const content = stageContent(ctx.manifest.profile);\n const solidSamples = ctx.bundle.maskSamples\n .flatMap((s) => s.rects.filter((r) => r.style === 'solid').map((r) => ({ t: s.t, r })))\n .filter((_, i, arr) => i % Math.max(1, Math.floor(arr.length / 3)) === 0)\n .slice(0, 3);\n let outSampled = 0;\n let outCovered = 0;\n for (const s of solidSamples) {\n const tOut = outTimeForSrc(ctx.manifest.segments, s.t);\n if (tOut === null || tOut >= ctx.manifest.durationMs - 100) continue;\n const cam = sampleCamera(ctx.manifest.camera, tOut);\n // mask rects are stored in FRAME px — back to viewport, then through the camera.\n const rectVp: Rect = { x: s.r.x / frameScale, y: s.r.y / frameScale, w: s.r.w / frameScale, h: s.r.h / frameScale };\n const proj = projectRect(rectVp, cam, p);\n const projFrame: Rect = { x: proj.x + content.x + 4, y: proj.y + content.y + 4, w: proj.w - 8, h: proj.h - 8 };\n if (projFrame.w < 12 || projFrame.h < 12) continue;\n const png = await extractFrameAt(ctx.videoPath, tOut).catch(() => null);\n if (!png) continue;\n const region = await regionGray48(png, projFrame);\n if (!region) continue;\n outSampled += 1;\n if (Math.sqrt(variance(region)) < 16) outCovered += 1; // solid fill + jpeg noise + spotlight dim\n }\n if (outSampled > 0 && outCovered === 0) {\n return {\n id: 'masks',\n status: 'fail',\n details: `masked regions verified in SOURCE frames but NOT covered in the delivered video (${outSampled} output sample(s) show content)`,\n };\n }\n\n const parts: string[] = [];\n if (buckets.size > 0) parts.push(`${buckets.size} solid region(s) verified opaque`);\n if (blurKeys.size > 0) parts.push(`${blurKeys.size} blurred region(s) applied`);\n if (outSampled > 0) parts.push(`${outCovered}/${outSampled} re-verified in the output video`);\n return { id: 'masks', status: 'pass', details: `${parts.join(', ')}; log clean` };\n}\n\nfunction scaleRect(r: Rect, s: number): Rect {\n return { x: r.x * s, y: r.y * s, w: r.w * s, h: r.h * s };\n}\n\nfunction rectsOverlap(a: Rect, b: Rect): boolean {\n return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;\n}\n\nfunction shrinkRect(r: { x: number; y: number; w: number; h: number }, by: number): Rect {\n return { x: r.x + by, y: r.y + by, w: Math.max(1, r.w - 2 * by), h: Math.max(1, r.h - 2 * by) };\n}\n\nfunction fmtRect(r: Rect): string {\n return `[${r.x.toFixed(0)},${r.y.toFixed(0)} ${r.w.toFixed(0)}x${r.h.toFixed(0)}]`;\n}\n\n/**\n * 10. The DELIVERED pixels match the plan: for sampled steps, the region of the output MP4\n * where the subject should be must correlate with the same region of the source bundle frame.\n * Every geometry check above re-runs the planner's math — this one closes the plan-vs-pixels\n * hole: a renderer drawing the wrong frame or the wrong crop fails HERE.\n */\nexport async function checkOutputPixels(ctx: VerifyContext): Promise<CheckResult> {\n const p = plane(ctx);\n const content = stageContent(ctx.manifest.profile);\n const frameScale = ctx.bundle.manifest.frameW / ctx.manifest.viewport.w;\n const captions = ctx.manifest.overlays.filter((o) => o.kind === 'caption');\n\n const candidates = ctx.manifest.steps.filter((s) => !s.masked && (s.focusRectVp ?? s.targetRectVp));\n // Sample evenly, capped for speed — this decodes output frames.\n const stride = Math.max(1, Math.floor(candidates.length / 6));\n const sampled = candidates.filter((_, i) => i % stride === 0).slice(0, 6);\n if (sampled.length === 0) return { id: 'output-pixels', status: 'skip', details: 'no steps with targets' };\n\n const evidence: CheckEvidence[] = [];\n let checked = 0;\n for (const step of sampled) {\n const rect = step.focusRectVp ?? step.targetRectVp!;\n const tOut = Math.max(step.outBeat + 100, step.outEnd - 250);\n const cam = sampleCamera(ctx.manifest.camera, tOut);\n const proj = projectRect(rect, cam, p);\n const projFrame: Rect = { x: proj.x + content.x, y: proj.y + content.y, w: proj.w, h: proj.h };\n // A caption overlapping the region would pollute the comparison — skip those samples.\n if (captions.some((c) => tOut >= c.tStart && tOut <= c.tEnd && rectsOverlap(c.box, projFrame))) continue;\n const { srcAt } = sampleSource(ctx.manifest.segments, tOut);\n if (srcAt === null) continue;\n\n const outPng = await extractFrameAt(ctx.videoPath, tOut).catch(() => null);\n if (!outPng) continue;\n const outRegion = await regionGray48(outPng, projFrame);\n const srcFile = framePath(ctx.bundle, frameIndexForTime(ctx.bundle.frames, srcAt));\n const srcRegion = await regionGray48(srcFile, {\n x: rect.x * frameScale,\n y: rect.y * frameScale,\n w: rect.w * frameScale,\n h: rect.h * frameScale,\n });\n if (!outRegion || !srcRegion) continue;\n // A flat (zero-variance) region proves nothing: it can be a legitimately blank area, a mask\n // overlay, or a transition frame — and correlation against flatness is undefined. Only a\n // TEXTURED-vs-TEXTURED mismatch demonstrates a wrong frame or wrong crop.\n if (variance(outRegion) < 4 || variance(srcRegion) < 4) continue;\n checked += 1;\n const corr = normalizedCorrelation(outRegion, srcRegion);\n // Loose threshold: JPEG, rescaling, frame blending, and the spotlight all perturb pixels;\n // a WRONG frame or crop scores near zero, a right-but-processed one scores high.\n if (corr < 0.5) {\n evidence.push({\n stepRef: step.stepRef,\n t: tOut,\n note: `output region does not match the planned source region (correlation ${corr.toFixed(2)})`,\n });\n }\n }\n if (checked === 0) return { id: 'output-pixels', status: 'skip', details: 'no comparable samples (captions overlapped or frames unavailable)' };\n return evidence.length > 0\n ? { id: 'output-pixels', status: 'fail', details: `${evidence.length}/${checked} sampled regions diverge from the plan`, evidence, coverage: { verified: checked - evidence.length, total: checked } }\n : { id: 'output-pixels', status: 'pass', details: `${checked} sampled output regions match their planned source`, coverage: { verified: checked, total: checked } };\n}\n","import { writeFile } from 'node:fs/promises';\nimport { createCanvas, loadImage } from '@napi-rs/canvas';\nimport type { ComposeManifest } from '../compose/types.js';\nimport { extractFrameAt } from './media.js';\nimport { registerFonts } from '../theme/index.js';\nimport { roundRect } from '../compose/overlays/text.js';\n\nconst TILE_W = 480;\nconst LABEL_H = 42;\nconst GUTTER = 16;\nconst COLS = 3;\n\n/**\n * Contact sheet: one tile per step at its action beat (decoded from the OUTPUT video —\n * what viewers actually see) plus first and last frames, annotated with captions.\n */\nexport async function renderContactSheet(\n manifest: ComposeManifest,\n videoPath: string,\n outPath: string,\n): Promise<string> {\n registerFonts();\n const tileH = Math.round((TILE_W * manifest.profile.height) / manifest.profile.width);\n const captionsByStep = new Map(\n manifest.overlays.filter((o) => o.kind === 'caption').map((o) => [o.stepRef, o]),\n );\n\n const moments: { t: number; label: string }[] = [\n { t: manifest.overlays.find((o) => o.kind === 'titleCard')!.tEnd / 2, label: 'Title' },\n ];\n for (const step of manifest.steps) {\n const caption = captionsByStep.get(step.stepRef);\n // Sample the SETTLED hold, not the beat: at the beat (+150ms) a slow effect — a navigation,\n // a fetch, a modal — hasn't painted yet, so the tile labelled \"Click Save\" would show the\n // screen from *before* Save was clicked. Sampling near the end of the step's hold shows the\n // effect the caption claims. (Clamped to stay after the beat for very short steps.)\n const label = caption ? `${caption.ordinal}. ${caption.text}` : `${step.kind} (${step.stepRef})`;\n const settled = Math.max(step.outBeat + 150, step.outEnd - 400);\n moments.push({ t: Math.min(settled, step.outEnd - 50), label });\n }\n moments.push({ t: manifest.durationMs - 200, label: 'Final state' });\n\n const rows = Math.ceil(moments.length / COLS);\n const width = GUTTER + COLS * (TILE_W + GUTTER);\n const height = GUTTER + rows * (tileH + LABEL_H + GUTTER);\n const canvas = createCanvas(width, height);\n const ctx = canvas.getContext('2d');\n ctx.fillStyle = '#14161d';\n ctx.fillRect(0, 0, width, height);\n\n for (let i = 0; i < moments.length; i++) {\n const m = moments[i]!;\n const col = i % COLS;\n const row = Math.floor(i / COLS);\n const x = GUTTER + col * (TILE_W + GUTTER);\n const y = GUTTER + row * (tileH + LABEL_H + GUTTER);\n try {\n const png = await extractFrameAt(videoPath, m.t);\n const img = await loadImage(png);\n ctx.drawImage(img, x, y, TILE_W, tileH);\n } catch {\n ctx.fillStyle = '#3a2030';\n ctx.fillRect(x, y, TILE_W, tileH);\n ctx.fillStyle = '#ffffff';\n ctx.font = '16px Inter Medium';\n ctx.textAlign = 'center';\n ctx.fillText('frame unavailable', x + TILE_W / 2, y + tileH / 2);\n }\n // Label bar\n ctx.fillStyle = '#1e222c';\n roundRect(ctx, x, y + tileH + 4, TILE_W, LABEL_H - 8, 6);\n ctx.fill();\n ctx.fillStyle = 'rgba(255,255,255,0.92)';\n ctx.font = '15px Inter Medium';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(truncate(m.label, 58), x + 12, y + tileH + 4 + (LABEL_H - 8) / 2 + 1);\n ctx.fillStyle = 'rgba(255,255,255,0.45)';\n ctx.font = '13px Inter';\n ctx.textAlign = 'right';\n ctx.fillText(`${(m.t / 1000).toFixed(1)}s`, x + TILE_W - 12, y + tileH + 4 + (LABEL_H - 8) / 2 + 1);\n }\n\n await writeFile(outPath, await canvas.encode('png'));\n return outPath;\n}\n\nfunction truncate(s: string, n: number): string {\n return s.length <= n ? s : s.slice(0, n - 1) + '…';\n}\n","import { readFile } from 'node:fs/promises';\nimport type { CheckResult } from './types.js';\nimport type { ComposeManifest } from '../compose/types.js';\nimport { log } from '../shared/log.js';\n\nconst DEFAULT_MODEL = process.env.PLAYHEAD_VISION_MODEL ?? 'claude-opus-5';\n\nexport interface VisionReview {\n model: string;\n findings: { severity: string; note: string }[];\n}\n\n/**\n * Optional AI review: sends the contact sheet to Claude for a judgment call the\n * deterministic checks can't make (\"does this read as a coherent, professional\n * walkthrough?\"). Advisory only — findings become warn-level check entries.\n */\nexport async function visionReview(\n contactSheetPath: string,\n manifest: ComposeManifest,\n): Promise<{ check: CheckResult; review: VisionReview | null }> {\n if (!process.env.ANTHROPIC_API_KEY) {\n return {\n check: { id: 'vision-review', status: 'skip', details: 'ANTHROPIC_API_KEY not set' },\n review: null,\n };\n }\n try {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const client = new Anthropic();\n const png = await readFile(contactSheetPath);\n const captions = manifest.overlays\n .filter((o) => o.kind === 'caption')\n .map((o) => `${o.ordinal}. ${o.text}`)\n .join('\\n');\n\n const response = await client.messages.create({\n model: DEFAULT_MODEL,\n max_tokens: 1200,\n messages: [\n {\n role: 'user',\n content: [\n {\n type: 'image',\n source: { type: 'base64', media_type: 'image/png', data: png.toString('base64') },\n },\n {\n type: 'text',\n text: [\n 'This is a contact sheet of key moments from an automatically produced product walkthrough video.',\n 'Each tile shows the output frame at one step, labeled with its instruction caption. The steps are:',\n captions,\n '',\n 'Review it as a demanding video editor. Report only real problems a viewer would notice:',\n 'illegible or clipped UI, captions that do not match what is on screen, awkward framing,',\n 'visual glitches, or anything unprofessional. Ignore the tile borders and labels themselves.',\n 'Respond with strict JSON: {\"findings\": [{\"severity\": \"warn\", \"note\": \"...\"}]} —',\n 'an empty findings array if the video looks publishable.',\n ].join('\\n'),\n },\n ],\n },\n ],\n });\n const text = response.content\n .map((b) => (b.type === 'text' ? b.text : ''))\n .join('');\n const parsed = extractJson(text);\n const findings = Array.isArray(parsed?.findings)\n ? parsed.findings\n .filter((f): f is { severity?: string; note?: string } => !!f && typeof f === 'object')\n .map((f) => ({ severity: String(f.severity ?? 'warn'), note: String(f.note ?? '') }))\n : [];\n const review: VisionReview = { model: DEFAULT_MODEL, findings };\n return {\n check: {\n id: 'vision-review',\n status: findings.length > 0 ? 'warn' : 'pass',\n details:\n findings.length > 0\n ? `${findings.length} advisory finding(s) from ${DEFAULT_MODEL}`\n : `no issues flagged by ${DEFAULT_MODEL}`,\n ...(findings.length > 0 ? { evidence: findings.map((f) => ({ note: f.note })) } : {}),\n },\n review,\n };\n } catch (e) {\n log.warn(`vision review failed: ${(e as Error).message}`);\n return {\n check: { id: 'vision-review', status: 'skip', details: `vision review errored: ${(e as Error).message}` },\n review: null,\n };\n }\n}\n\nfunction extractJson(text: string): { findings?: unknown[] } | null {\n const start = text.indexOf('{');\n const end = text.lastIndexOf('}');\n if (start === -1 || end <= start) return null;\n try {\n return JSON.parse(text.slice(start, end + 1)) as { findings?: unknown[] };\n } catch {\n return null;\n }\n}\n","import { createHmac, createHash, sign as edSign, verify as edVerify, createPrivateKey, createPublicKey, type KeyObject } from 'node:crypto';\nimport { readFileSync } from 'node:fs';\nimport type { Verdict, VerdictSignature } from './types.js';\n\n/**\n * The canonical signable payload. Round-2 audit: the v1 payload signed only {id, status} per\n * check — evidence text, the contact sheet, the compose manifest, and the failure reason were\n * all rewritable after signing. v2 covers everything a consumer relies on. Paths are excluded —\n * moving files doesn't change what was proven.\n */\nexport function signablePayload(v: Omit<Verdict, 'signature'>): string {\n return JSON.stringify({\n schema: v.schema,\n verdict: v.verdict,\n videoSha256: v.video.sha256,\n manifestHash: v.manifestHash,\n contactSheetSha256: v.contactSheetSha256,\n bundleHashes: { events: v.bundleHashes.events, framesIndex: v.bundleHashes.framesIndex },\n coverage: v.coverage,\n provenance: {\n playheadVersion: v.provenance.playheadVersion,\n specHash: v.provenance.specHash,\n appUrl: v.provenance.appUrl,\n capturedAt: v.provenance.capturedAt,\n verifiedAt: v.provenance.verifiedAt,\n checkSuiteVersion: v.provenance.checkSuiteVersion,\n host: v.provenance.host,\n partial: v.provenance.partial ?? false,\n failure: v.provenance.failure ?? null,\n },\n checks: v.checks.map((c) => ({\n id: c.id,\n status: c.status,\n details: c.details,\n evidence: (c.evidence ?? []).map((e) => ({ stepRef: e.stepRef ?? null, t: e.t ?? null, note: e.note })),\n })),\n vision: v.vision,\n });\n}\n\n/**\n * Sign a verdict. Two schemes, resolved from the environment:\n * - PLAYHEAD_SIGNING_KEY_FILE → Ed25519 (asymmetric): consumers verify against the public key\n * and PIN the key id — the producer cannot be impersonated by anyone who can merely verify.\n * Generate a key with `playhead keygen`.\n * - PLAYHEAD_SIGNING_KEY → HMAC-SHA256 (symmetric, zero-config): tamper-evidence only; anyone\n * holding the key can also mint verdicts. Fine within one trust domain.\n * Ed25519 wins when both are set. Returns null when neither is configured.\n */\nexport function signVerdict(\n v: Omit<Verdict, 'signature'>,\n env: { hmacKey?: string; keyFile?: string } = {\n ...(process.env.PLAYHEAD_SIGNING_KEY ? { hmacKey: process.env.PLAYHEAD_SIGNING_KEY } : {}),\n ...(process.env.PLAYHEAD_SIGNING_KEY_FILE ? { keyFile: process.env.PLAYHEAD_SIGNING_KEY_FILE } : {}),\n },\n): VerdictSignature | null {\n const payload = Buffer.from(signablePayload(v));\n if (env.keyFile) {\n const privateKey = createPrivateKey(readFileSync(env.keyFile, 'utf8'));\n const publicKey = createPublicKey(privateKey);\n const spki = publicKey.export({ type: 'spki', format: 'der' });\n return {\n alg: 'Ed25519',\n keyId: keyIdFor(spki),\n publicKey: spki.toString('base64'),\n value: edSign(null, payload, privateKey).toString('base64'),\n };\n }\n if (env.hmacKey) {\n return {\n alg: 'HS256',\n keyId: keyIdFor(Buffer.from(env.hmacKey)),\n value: createHmac('sha256', env.hmacKey).update(payload).digest('hex'),\n };\n }\n return null;\n}\n\n/** Verify a verdict's signature. For Ed25519 the embedded public key is used — this proves the\n * verdict is INTACT and was signed by the holder of keyId's private key; whether that key is\n * trusted is the consumer's pinning decision. For HS256 the shared key must be provided. */\nexport function verifySignature(\n v: Verdict,\n opts: { hmacKey?: string } = {},\n): { valid: boolean; reason: string } {\n if (!v.signature) return { valid: false, reason: 'verdict is unsigned' };\n const payload = Buffer.from(signablePayload(stripSignature(v)));\n if (v.signature.alg === 'Ed25519') {\n if (!v.signature.publicKey) return { valid: false, reason: 'Ed25519 signature missing its public key' };\n const key: KeyObject = createPublicKey({\n key: Buffer.from(v.signature.publicKey, 'base64'),\n type: 'spki',\n format: 'der',\n });\n const ok = edVerify(null, payload, key, Buffer.from(v.signature.value, 'base64'));\n return ok\n ? { valid: true, reason: `Ed25519 signature valid for key ${v.signature.keyId} — pin this key id to trust the producer` }\n : { valid: false, reason: 'Ed25519 SIGNATURE MISMATCH — the verdict was modified after signing' };\n }\n if (v.signature.alg === 'HS256') {\n const key = opts.hmacKey ?? process.env.PLAYHEAD_SIGNING_KEY;\n if (!key) return { valid: false, reason: 'HS256 verdict but PLAYHEAD_SIGNING_KEY is not set — cannot check' };\n const expect = createHmac('sha256', key).update(payload).digest('hex');\n return expect === v.signature.value\n ? { valid: true, reason: `HS256 signature valid (key ${v.signature.keyId}) — note: symmetric, proves integrity within the key's trust domain only` }\n : { valid: false, reason: 'HS256 SIGNATURE MISMATCH — the verdict was modified after signing (or a different key)' };\n }\n return { valid: false, reason: `unknown signature algorithm ${(v.signature as { alg: string }).alg}` };\n}\n\nfunction stripSignature(v: Verdict): Omit<Verdict, 'signature'> {\n const { signature: _sig, ...rest } = v;\n return rest;\n}\n\nexport function keyIdFor(material: Buffer): string {\n return createHash('sha256').update(material).digest('hex').slice(0, 16);\n}\n\n/** JUnit XML: one testsuite per verdict, one testcase per check — the shape every CI ingests. */\nexport function toJUnit(v: Verdict, suiteName = 'playhead'): string {\n const failures = v.checks.filter((c) => c.status === 'fail').length;\n const skipped = v.checks.filter((c) => c.status === 'skip').length;\n const cases = v.checks\n .map((c) => {\n const body =\n c.status === 'fail'\n ? `\\n <failure message=\"${escXml(c.details)}\">${escXml(\n (c.evidence ?? []).map((e) => `${e.stepRef ?? ''}${e.t !== undefined ? ` @${(e.t / 1000).toFixed(1)}s` : ''} — ${e.note}`).join('\\n'),\n )}</failure>\\n `\n : c.status === 'skip'\n ? `\\n <skipped message=\"${escXml(c.details)}\"/>\\n `\n : '';\n return ` <testcase classname=\"${escXml(suiteName)}\" name=\"${escXml(c.id)}\">${body}</testcase>`;\n })\n .join('\\n');\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuite name=\"${escXml(suiteName)}\" tests=\"${v.checks.length}\" failures=\"${failures}\" skipped=\"${skipped}\">\n${cases}\n</testsuite>\n`;\n}\n\n/** JUnit for a FLOW failure (the app broke; no verdict exists) — CI still gets a report. */\nexport function flowFailureJUnit(failure: { stepRef: string; message: string }, suiteName = 'playhead'): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuite name=\"${escXml(suiteName)}\" tests=\"1\" failures=\"1\" skipped=\"0\">\n <testcase classname=\"${escXml(suiteName)}\" name=\"flow\">\n <failure message=\"${escXml(`flow failed at ${failure.stepRef}`)}\">${escXml(failure.message)}</failure>\n </testcase>\n</testsuite>\n`;\n}\n\nfunction escXml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n"],"mappings":"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","names":["ctx","join","count","createHash","join","dirname","join","createHash","plane","join","sleep","writeFile","round1","readFile","join","join","writeFile","existsSync","join","dirname","createRequire","require","log","log","log","plane","shot","log","plan","log","lowerFirst","createCanvas","ctx","ctx","sharp","createCanvas","sharp","createCanvas","ctx","spawn","createRequire","require","spawn","plane","createCanvas","ctx","sharp","sharp","mkdir","writeFile","existsSync","join","createHash","createRequire","require","ffprobePath","execFile","promisify","mkdir","existsSync","join","createRequire","require","createRequire","ffmpegPath","exec","promisify","execFile","mkdir","join","existsSync","join","writeFile","join","mkdir","writeFile","readFile","CLICK_KINDS","ctx","rect","writeFile","createCanvas","createCanvas","ctx","truncate","writeFile","readFile","readFile","createHash","readFileSync","createHash","pc","join","mkdir","ctx","writeFile","pc"]}
|