saccade 0.0.1
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/README.md +135 -0
- package/dist/core.cjs +1736 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +276 -0
- package/dist/core.d.ts +276 -0
- package/dist/core.mjs +1703 -0
- package/dist/core.mjs.map +1 -0
- package/dist/index.cjs +2822 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +152 -0
- package/dist/index.d.ts +152 -0
- package/dist/index.mjs +2791 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/timing.ts","../src/core/recorder.ts","../src/core/scrubber.ts","../src/core/export.ts","../src/core/engine.ts"],"sourcesContent":["/**\n * Timing controller — patches all JS timing APIs to respect a speed factor.\n *\n * At 0.5x speed, a 100ms setTimeout becomes 200ms real time, and\n * performance.now() / rAF timestamps advance at half rate.\n */\n\nexport class TimingController {\n private speed = 1\n private realBaseline: number\n private virtualBaseline = 0\n private intervalMap = new Map<number, { handler: TimerHandler; delay: number; realId: number }>()\n private nextIntervalId = 1_000_000\n private mediaObserver: MutationObserver | null = null\n private animObserver: number | null = null\n private _origAnimate: typeof Element.prototype.animate | null = null\n private installed = false\n\n // Preserved originals\n private _raf: typeof requestAnimationFrame\n private _caf: typeof cancelAnimationFrame\n private _setTimeout: typeof setTimeout\n private _clearTimeout: typeof clearTimeout\n private _setInterval: typeof setInterval\n private _clearInterval: typeof clearInterval\n private _perfNow: () => number\n private _dateNow: () => number\n\n constructor() {\n this._raf = requestAnimationFrame.bind(window)\n this._caf = cancelAnimationFrame.bind(window)\n this._setTimeout = setTimeout.bind(window)\n this._clearTimeout = clearTimeout.bind(window)\n this._setInterval = setInterval.bind(window)\n this._clearInterval = clearInterval.bind(window)\n this._perfNow = performance.now.bind(performance)\n this._dateNow = Date.now\n this.realBaseline = this._perfNow()\n }\n\n private getVirtualTime(): number {\n const realElapsed = this._perfNow() - this.realBaseline\n return this.virtualBaseline + realElapsed * this.speed\n }\n\n private reanchor(): void {\n const virtualNow = this.getVirtualTime()\n this.realBaseline = this._perfNow()\n this.virtualBaseline = virtualNow\n }\n\n /** Install timing patches. Safe to call multiple times. */\n install(): void {\n if (this.installed) return\n this.installed = true\n\n const self = this\n\n // Expose original rAF for the recorder's capture loop\n ;(window as any).__LAPSE_ORIGINAL_RAF__ = this._raf\n\n // Intercept Element.prototype.animate to set playbackRate on creation\n const origAnimate = Element.prototype.animate\n this._origAnimate = origAnimate\n Element.prototype.animate = function (...args: Parameters<typeof origAnimate>) {\n const anim = origAnimate.apply(this, args)\n if (self.speed !== 1) {\n anim.playbackRate = self.speed || 0.001\n }\n return anim\n }\n\n // performance.now()\n performance.now = () => self.getVirtualTime()\n\n // Date.now()\n const dateBaseline = this._dateNow()\n Date.now = () => dateBaseline + self.getVirtualTime()\n\n // requestAnimationFrame\n window.requestAnimationFrame = (callback: FrameRequestCallback): number => {\n return self._raf(() => {\n callback(self.getVirtualTime())\n })\n }\n window.cancelAnimationFrame = this._caf\n\n // setTimeout\n window.setTimeout = ((handler: TimerHandler, delay?: number, ...args: any[]): number => {\n const scaledDelay = (delay ?? 0) / (self.speed || 1)\n return self._setTimeout(handler, scaledDelay, ...args) as unknown as number\n }) as typeof window.setTimeout\n\n window.clearTimeout = this._clearTimeout\n\n // setInterval — re-register on each tick to pick up speed changes\n window.setInterval = ((handler: TimerHandler, delay?: number, ...args: any[]): number => {\n const id = self.nextIntervalId++\n const baseDelay = delay ?? 0\n\n function tick() {\n const scaledDelay = baseDelay / (self.speed || 1)\n const realId = self._setTimeout(() => {\n if (typeof handler === 'function') {\n ;(handler as Function)(...args)\n }\n if (self.intervalMap.has(id)) tick()\n }, scaledDelay) as unknown as number\n const entry = self.intervalMap.get(id)\n if (entry) entry.realId = realId\n }\n\n self.intervalMap.set(id, { handler, delay: baseDelay, realId: 0 })\n tick()\n return id\n }) as typeof window.setInterval\n\n window.clearInterval = ((id?: number): void => {\n if (id == null) return\n const entry = self.intervalMap.get(id)\n if (entry) {\n self._clearTimeout(entry.realId as any)\n self.intervalMap.delete(id)\n } else {\n self._clearInterval(id)\n }\n }) as typeof window.clearInterval\n\n // Media elements\n this.mediaObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (node instanceof HTMLVideoElement || node instanceof HTMLAudioElement) {\n node.playbackRate = self.speed\n }\n }\n }\n })\n if (document.body) {\n this.mediaObserver.observe(document.body, { childList: true, subtree: true })\n }\n }\n\n /** Set playback speed. Requires install() first. */\n setSpeed(newSpeed: number): void {\n if (!this.installed) this.install()\n this.reanchor()\n this.speed = newSpeed\n // Patch existing media elements\n document.querySelectorAll('video, audio').forEach((el) => {\n ;(el as HTMLMediaElement).playbackRate = newSpeed\n })\n // Set playbackRate on all running CSS transitions and animations\n this.patchAnimations()\n }\n\n /** Patch playbackRate on all active CSS transitions/animations via WAAPI. */\n private patchAnimations(): void {\n try {\n const anims = document.getAnimations()\n for (const anim of anims) {\n // Skip animations on Lapse's own UI\n const target = (anim.effect as KeyframeEffect)?.target as HTMLElement | null\n if (target?.closest?.('[data-lapse-panel]')) continue\n anim.playbackRate = this.speed || 0.001 // 0 pauses, use near-zero instead\n }\n } catch {}\n\n // Also watch for new animations starting\n if (!this.animObserver) {\n this.animObserver = this._setInterval(() => {\n if (!this.installed) return\n try {\n const anims = document.getAnimations()\n for (const anim of anims) {\n const target = (anim.effect as KeyframeEffect)?.target as HTMLElement | null\n if (target?.closest?.('[data-lapse-panel]')) continue\n if (anim.playbackRate !== this.speed) {\n anim.playbackRate = this.speed || 0.001\n }\n }\n } catch {}\n }, 100) as unknown as number\n }\n }\n\n getSpeed(): number {\n return this.speed\n }\n\n /** Restore all patched APIs to originals. */\n destroy(): void {\n if (!this.installed) return\n\n performance.now = this._perfNow\n Date.now = this._dateNow\n window.requestAnimationFrame = this._raf\n window.cancelAnimationFrame = this._caf\n window.setTimeout = this._setTimeout\n window.clearTimeout = this._clearTimeout\n window.setInterval = this._setInterval\n window.clearInterval = this._clearInterval\n\n // Clear all managed intervals\n for (const [, entry] of this.intervalMap) {\n this._clearTimeout(entry.realId as any)\n }\n this.intervalMap.clear()\n\n if (this._origAnimate) {\n Element.prototype.animate = this._origAnimate\n this._origAnimate = null\n }\n\n this.mediaObserver?.disconnect()\n this.mediaObserver = null\n\n if (this.animObserver != null) {\n this._clearInterval(this.animObserver as any)\n this.animObserver = null\n }\n\n // Restore playbackRate on all animations\n try {\n for (const anim of document.getAnimations()) {\n anim.playbackRate = 1\n }\n } catch {}\n\n delete (window as any).__LAPSE_ORIGINAL_RAF__\n this.installed = false\n }\n}\n","import type {\n AnimationInfo,\n ElementSnapshot,\n FrameAnimation,\n FrameSnapshot,\n PropertySnapshot,\n Rect,\n TimelineCapture,\n} from './types'\n\n// ---------------------------------------------------------------------------\n// Augment Window for Lapse internals\n// ---------------------------------------------------------------------------\n\ndeclare global {\n interface Window {\n __LAPSE_ORIGINAL_RAF__?: typeof requestAnimationFrame\n }\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Visual-only properties — safe to override without affecting layout. */\nconst SAFE_PROPS = [\n 'opacity', 'transform', 'background-color', 'color', 'border-color',\n 'box-shadow', 'border-radius', 'filter', 'clip-path',\n 'scale', 'rotate', 'translate',\n 'outline-color', 'outline-width', 'outline-offset', 'outline-style',\n 'text-decoration-color',\n 'fill', 'stroke', 'stroke-dasharray', 'stroke-dashoffset',\n 'visibility', 'pointer-events',\n]\n\n/** Properties that affect layout — snapshot only, applied only on animated elements. */\nconst LAYOUT_PROPS = [\n 'width', 'height', 'top', 'left', 'right', 'bottom',\n 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',\n 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',\n 'max-height', 'max-width', 'min-height', 'min-width',\n 'display',\n]\n\nconst SNAPSHOT_PROPS = [...SAFE_PROPS, ...LAYOUT_PROPS]\n\nconst SAFE_PROPS_SET = new Set(SAFE_PROPS)\n\nconst SNAPSHOT_ATTRS = [\n 'data-state', 'data-checked', 'data-disabled', 'data-highlighted',\n 'data-orientation', 'data-active', 'data-selected', 'data-open',\n 'data-closed', 'data-side', 'data-align', 'data-focus', 'data-hover',\n 'data-at-boundary', 'data-scrubbing',\n 'aria-checked', 'aria-selected', 'aria-expanded', 'aria-pressed',\n 'aria-hidden', 'aria-disabled', 'aria-valuenow', 'aria-valuemin', 'aria-valuemax',\n 'aria-invalid',\n 'checked', 'disabled', 'hidden', 'value',\n 'class', 'style',\n]\n\nconst STATE_SELECTORS = [\n '[data-state]', '[aria-checked]', '[aria-selected]', '[aria-expanded]',\n '[aria-pressed]', '[role=\"radio\"]', '[role=\"checkbox\"]', '[role=\"switch\"]',\n '[role=\"tab\"]', '[role=\"tabpanel\"]', '[role=\"option\"]', '[role=\"slider\"]',\n '[role=\"menuitem\"]', '[role=\"menuitemcheckbox\"]', '[role=\"menuitemradio\"]',\n '[type=\"radio\"]', '[type=\"checkbox\"]', '[type=\"range\"]',\n 'input', 'button', 'select', 'textarea',\n '[data-radix-collection-item]',\n '[data-slot=\"slider-thumb\"]', '[data-slot=\"slider-track\"]',\n].join(',')\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Build a stable structural selector for `el` (up to 5 ancestors).\n * Used as the element identity key throughout recording & scrubbing.\n */\nfunction getSelector(el: Element): string | null {\n if (!el || !el.tagName) return null\n const parts: string[] = []\n let current: Element | null = el\n for (let i = 0; i < 5 && current && current.tagName && current.tagName !== 'HTML'; i++) {\n const tag = current.tagName.toLowerCase()\n const parent: Element | null = current.parentElement\n if (parent) {\n const siblings = Array.from(parent.children)\n const idx = siblings.indexOf(current) + 1\n parts.unshift(tag + ':nth-child(' + idx + ')')\n } else {\n parts.unshift(tag)\n }\n current = parent\n }\n return parts.join(' > ')\n}\n\nfunction getReadableSelector(el: Element): string {\n if (!el || !el.tagName) return 'unknown'\n if (el.id) return '#' + el.id\n const tag = el.tagName.toLowerCase()\n const classes = Array.from(el.classList || []).slice(0, 3).map((c) => '.' + c).join('')\n return tag + classes\n}\n\nfunction getElementLabel(el: Element): string {\n if (!el) return 'unknown'\n const ariaLabel = el.getAttribute('aria-label')\n if (ariaLabel) return ariaLabel\n const text = (el.textContent || '').trim()\n if (text && text.length < 40 && text.length > 0) return text\n const label = el.closest('label') || el.closest('[aria-label]')\n if (label) {\n const lt = label.getAttribute('aria-label') || (label.textContent || '').trim()\n if (lt && lt.length < 40) return lt\n }\n const state = el.getAttribute('data-state')\n const role = el.getAttribute('role')\n if (role && state) return role + ' (' + state + ')'\n if (role) return role\n return getReadableSelector(el)\n}\n\n/**\n * Parenthesis-aware comma split — keeps `cubic-bezier(...)` as atomic tokens.\n */\nfunction cssSplit(str: string): string[] {\n const parts: string[] = []\n let depth = 0\n let start = 0\n for (let i = 0; i < str.length; i++) {\n if (str[i] === '(') depth++\n else if (str[i] === ')') depth--\n else if (str[i] === ',' && depth === 0) {\n parts.push(str.slice(start, i).trim())\n start = i + 1\n }\n }\n parts.push(str.slice(start).trim())\n return parts\n}\n\n// ---------------------------------------------------------------------------\n// TimelineRecorder\n// ---------------------------------------------------------------------------\n\nexport class TimelineRecorder {\n // ---- Recording state ----------------------------------------------------\n private recording = false\n private startTime = 0\n private boundingBox: Rect | null = null\n\n /** Structural-selector -> live DOM element. */\n readonly elements = new Map<string, HTMLElement>()\n /** Animation id -> info. */\n readonly animations = new Map<string, AnimationInfo>()\n /** Original inline style per element (captured on first encounter). */\n private originalStyles = new Map<string, string>()\n /** Captured frames. */\n private frames: FrameSnapshot[] = []\n\n // ---- Portal management --------------------------------------------------\n private activePortals = new Map<string, { element: HTMLElement }>()\n private portalIdCounter = 0\n private currentPortalIds = new Set<string>()\n private capturedPortals = new Set<string>()\n\n // ---- JS animation detection (Phase 2) -----------------------------------\n private prevInlineStyles = new Map<string, Record<string, string>>()\n private jsAnimStartTimes = new Map<string, number>()\n private jsAnimLastSeen = new Map<string, number>()\n private jsAnimFromValues = new Map<string, string>()\n private jsAnimChangeCount = new Map<string, number>()\n\n // ---- Interaction state --------------------------------------------------\n private currentHoverEls = new Set<string>()\n private currentFocusSel: string | null = null\n private currentPointer = { x: 0, y: 0, buttons: 0 }\n\n // ---- Observers & listeners ----------------------------------------------\n private attrObserver: MutationObserver | null = null\n private portalObserver: MutationObserver | null = null\n private exitObserver: MutationObserver | null = null\n\n private onMouseOver: ((e: MouseEvent) => void) | null = null\n private onMouseOut: ((e: MouseEvent) => void) | null = null\n private onFocusIn: ((e: FocusEvent) => void) | null = null\n private onFocusOut: (() => void) | null = null\n private onPointerMove: ((e: PointerEvent) => void) | null = null\n private onPointerDown: ((e: PointerEvent) => void) | null = null\n private onPointerUp: ((e: PointerEvent) => void) | null = null\n\n // ---- WAAPI interception --------------------------------------------------\n /** Animations captured via Element.prototype.animate monkey-patch. */\n readonly interceptedAnimations: { animation: Animation; target: Element }[] = []\n\n // ---- Recording limits ---------------------------------------------------\n private static readonly MAX_DURATION_MS = 60_000\n private static readonly MAX_FRAMES = 3600\n private hiddenSince: number | null = null\n private onVisibilityChange: (() => void) | null = null\n /** Set to true when the capture loop self-terminates due to limits. */\n autoStopped = false\n /** Called when recording auto-stops. Set by the engine. */\n onAutoStop: (() => void) | null = null\n\n // ---- Saved originals (for restoration) ----------------------------------\n private _removeChild: typeof Node.prototype.removeChild | null = null\n private _remove: typeof Element.prototype.remove | null = null\n private _elementAnimate: typeof Element.prototype.animate | null = null\n\n // ---- DOM elements injected during stop ----------------------------------\n /** `<style>` that disables all transitions/animations after recording. */\n noTransitionsEl: HTMLStyleElement | null = null\n /** Full-screen overlay blocking interaction during scrub. */\n blockerEl: HTMLDivElement | null = null\n /** `<style>` with cloned :hover / :focus rules rewritten as `[data-lapse-*]`. */\n lapseStyleEl: HTMLStyleElement | null = null\n\n // ---- Unpatched rAF reference --------------------------------------------\n private get _raf(): typeof requestAnimationFrame {\n return (window as any).__LAPSE_ORIGINAL_RAF__ || requestAnimationFrame\n }\n\n // =========================================================================\n // Public API — helpers exposed for the scrubber\n // =========================================================================\n\n getSelector = getSelector\n\n get SAFE_PROPS_SET(): Set<string> {\n return SAFE_PROPS_SET\n }\n\n get capturedPortalIds(): Set<string> {\n return this.capturedPortals\n }\n\n // =========================================================================\n // startRecording\n // =========================================================================\n\n startRecording(boundingBox?: Rect | null): void {\n if (this.recording) return\n\n // Reset state\n this.recording = true\n this.autoStopped = false\n this.hiddenSince = null\n this.startTime = performance.now()\n this.frames = []\n this.animations.clear()\n this.elements.clear()\n this.originalStyles.clear()\n this.boundingBox = boundingBox || null\n this.activePortals.clear()\n this.portalIdCounter = 0\n this.currentPortalIds.clear()\n this.capturedPortals.clear()\n this.prevInlineStyles.clear()\n this.jsAnimStartTimes.clear()\n this.jsAnimLastSeen.clear()\n this.jsAnimFromValues.clear()\n this.jsAnimChangeCount.clear()\n this.currentHoverEls.clear()\n this.currentFocusSel = null\n this.currentPointer = { x: 0, y: 0, buttons: 0 }\n\n // Visibility tracking — auto-stop when tab hidden >5s\n this.onVisibilityChange = () => {\n if (!this.recording) return\n if (document.hidden) {\n this.hiddenSince = performance.now()\n } else {\n this.hiddenSince = null\n }\n }\n document.addEventListener('visibilitychange', this.onVisibilityChange)\n\n // ------------------------------------------------------------------\n // Element tracking\n // ------------------------------------------------------------------\n\n const trackElement = (el: Element): void => {\n if (!el || !(el as HTMLElement).tagName) return\n // Skip elements inside the Lapse panel\n if ((el as HTMLElement).closest?.('[data-lapse-panel]')) return\n const sel = getSelector(el)\n if (!sel) return\n const isNew = !this.elements.has(sel)\n this.elements.set(sel, el as HTMLElement)\n if (isNew) {\n this.originalStyles.set(sel, el.getAttribute('style') || '')\n }\n }\n\n const trackTree = (root: Element): void => {\n if (!root || !root.querySelectorAll) return\n trackElement(root)\n for (const child of root.querySelectorAll('*')) {\n trackElement(child)\n }\n }\n\n const isInBounds = (el: Element): boolean => {\n if ((el as HTMLElement).closest?.('[data-lapse-panel]')) return false\n if (!this.boundingBox) return true\n const r = el.getBoundingClientRect()\n const bb = this.boundingBox\n return (\n r.x < bb.x + bb.width &&\n r.x + r.width > bb.x &&\n r.y < bb.y + bb.height &&\n r.y + r.height > bb.y\n )\n }\n\n // ------------------------------------------------------------------\n // Pre-scan: track all interactive elements and their groups\n // ------------------------------------------------------------------\n\n try {\n const stateEls = document.querySelectorAll(STATE_SELECTORS)\n for (const el of stateEls) {\n if (!isInBounds(el)) continue\n trackElement(el)\n for (const child of el.querySelectorAll('*')) {\n trackElement(child)\n }\n const parent = el.parentElement\n if (parent) {\n trackElement(parent)\n for (const sibling of parent.children) {\n trackElement(sibling)\n for (const child of sibling.querySelectorAll('*')) {\n trackElement(child)\n }\n }\n }\n }\n } catch (_) {\n // Selector may fail in edge cases — not critical\n }\n\n // ------------------------------------------------------------------\n // Observers\n // ------------------------------------------------------------------\n\n // 1. Attribute-change observer\n this.attrObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.target instanceof HTMLElement) {\n trackElement(m.target)\n const parent = m.target.parentElement\n if (parent) {\n for (const sibling of parent.children) {\n trackElement(sibling)\n for (const child of sibling.querySelectorAll('*')) {\n trackElement(child)\n }\n }\n }\n }\n }\n })\n this.attrObserver.observe(document.body, {\n attributes: true,\n attributeFilter: [\n 'data-state', 'data-highlighted', 'data-hover', 'data-focus',\n 'data-active', 'data-selected', 'data-open', 'data-closed',\n 'data-at-boundary', 'data-scrubbing',\n 'aria-checked', 'aria-selected', 'aria-expanded', 'aria-valuenow',\n 'aria-invalid', 'class', 'style',\n ],\n subtree: true,\n })\n\n // 2. Portal management — intercept DOM removal to keep portals alive\n this._removeChild = Node.prototype.removeChild\n const savedRemoveChild = this._removeChild\n const self = this\n\n Node.prototype.removeChild = function <T extends Node>(child: T): T {\n if (\n self.recording &&\n child instanceof HTMLElement &&\n child.hasAttribute('data-lapse-portal-id')\n ) {\n child.style.display = 'none'\n child.setAttribute('data-lapse-portal-hidden', '')\n const id = child.getAttribute('data-lapse-portal-id')\n if (id) self.currentPortalIds.delete(id)\n return child\n }\n return savedRemoveChild.call(this, child) as T\n }\n\n this._remove = Element.prototype.remove\n const savedRemove = this._remove\n\n Element.prototype.remove = function (this: Element) {\n if (\n self.recording &&\n this instanceof HTMLElement &&\n this.hasAttribute('data-lapse-portal-id')\n ) {\n this.style.display = 'none'\n this.setAttribute('data-lapse-portal-hidden', '')\n const id = this.getAttribute('data-lapse-portal-id')\n if (id) self.currentPortalIds.delete(id)\n return\n }\n return savedRemove.call(this)\n }\n\n // Intercept Element.prototype.animate to track WAAPI animations\n this._elementAnimate = Element.prototype.animate\n const savedAnimate = this._elementAnimate\n\n Element.prototype.animate = function (\n this: Element,\n keyframes: Keyframe[] | PropertyIndexedKeyframes | null,\n options?: number | KeyframeAnimationOptions,\n ): Animation {\n const anim = savedAnimate.call(this, keyframes, options)\n\n // Track the target element and capture the animation\n if (self.recording && this instanceof HTMLElement && isInBounds(this)) {\n trackElement(this)\n self.interceptedAnimations.push({ animation: anim, target: this })\n }\n\n return anim\n }\n\n // Watch for new portals being added\n this.portalObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (const node of m.addedNodes) {\n if (!(node instanceof HTMLElement)) continue\n if (node.parentElement !== document.body) continue\n if (node.hasAttribute('data-lapse-portal-id')) continue // already tracked\n\n const isPortal =\n node.hasAttribute('data-radix-popper-content-wrapper') ||\n node.hasAttribute('data-radix-portal') ||\n node.getAttribute('role') === 'dialog' ||\n node.getAttribute('role') === 'alertdialog' ||\n node.querySelector(\n '[role=\"menu\"], [role=\"dialog\"], [role=\"alertdialog\"], ' +\n '[role=\"listbox\"], [role=\"tooltip\"], [data-radix-popper-content-wrapper]',\n ) ||\n node.hasAttribute('data-state') ||\n (node.style &&\n (node.style.position === 'fixed' || node.style.position === 'absolute')) ||\n getComputedStyle(node).position === 'fixed'\n\n if (!isPortal) continue\n\n const id = '__lapse_portal_' + this.portalIdCounter++\n node.setAttribute('data-lapse-portal-id', id)\n this.activePortals.set(id, { element: node })\n this.currentPortalIds.add(id)\n this.capturedPortals.add(id)\n trackTree(node)\n }\n }\n })\n this.portalObserver.observe(document.body, { childList: true })\n\n // Exit-animation observer — catch any tracked element being removed\n this.exitObserver = new MutationObserver((mutations) => {\n if (!this.recording) return\n for (const m of mutations) {\n for (const node of m.removedNodes) {\n if (!(node instanceof HTMLElement)) continue\n const sel = getSelector(node)\n if (sel && this.elements.has(sel)) {\n if (!node.isConnected) {\n node.style.display = 'none'\n node.setAttribute('data-lapse-exit-captured', '')\n ;(m.target || document.body).appendChild(node)\n }\n }\n }\n }\n })\n this.exitObserver.observe(document.body, { childList: true, subtree: true })\n\n // ------------------------------------------------------------------\n // 3. Mouse hover tracking\n // ------------------------------------------------------------------\n\n this.onMouseOver = (e: MouseEvent) => {\n if (!this.recording) return\n this.currentHoverEls.clear()\n let el = e.target as HTMLElement | null\n while (el && el !== document.body) {\n const sel = getSelector(el)\n if (sel) {\n this.currentHoverEls.add(sel)\n trackElement(el)\n }\n el = el.parentElement\n }\n }\n\n this.onMouseOut = (e: MouseEvent) => {\n if (!this.recording) return\n if (!e.relatedTarget || !document.body.contains(e.relatedTarget as Node)) {\n this.currentHoverEls.clear()\n }\n }\n\n document.addEventListener('mouseover', this.onMouseOver, true)\n document.addEventListener('mouseout', this.onMouseOut, true)\n\n // ------------------------------------------------------------------\n // 4. Focus tracking\n // ------------------------------------------------------------------\n\n this.onFocusIn = (e: FocusEvent) => {\n if (!this.recording) return\n const el = e.target as HTMLElement | null\n if (el && el !== document.body) {\n const sel = getSelector(el)\n this.currentFocusSel = sel\n trackElement(el)\n let parent = el.parentElement\n while (parent && parent !== document.body) {\n trackElement(parent)\n parent = parent.parentElement\n }\n }\n }\n\n this.onFocusOut = () => {\n if (!this.recording) return\n this.currentFocusSel = null\n }\n\n document.addEventListener('focusin', this.onFocusIn, true)\n document.addEventListener('focusout', this.onFocusOut, true)\n\n // ------------------------------------------------------------------\n // 5. Pointer position tracking (sliders, scrubbers)\n // ------------------------------------------------------------------\n\n this.onPointerMove = (e: PointerEvent) => {\n if (!this.recording) return\n this.currentPointer = { x: e.clientX, y: e.clientY, buttons: e.buttons }\n }\n\n this.onPointerDown = (e: PointerEvent) => {\n if (!this.recording) return\n this.currentPointer = { x: e.clientX, y: e.clientY, buttons: e.buttons }\n }\n\n this.onPointerUp = (e: PointerEvent) => {\n if (!this.recording) return\n this.currentPointer = { x: e.clientX, y: e.clientY, buttons: 0 }\n }\n\n document.addEventListener('pointermove', this.onPointerMove, true)\n document.addEventListener('pointerdown', this.onPointerDown, true)\n document.addEventListener('pointerup', this.onPointerUp, true)\n\n // ------------------------------------------------------------------\n // Capture loop\n // ------------------------------------------------------------------\n\n const captureFrame = (): void => {\n if (!this.recording) return\n\n const time = performance.now() - this.startTime\n\n // Auto-stop: max duration, max frames, or tab hidden >5s\n if (\n time >= TimelineRecorder.MAX_DURATION_MS ||\n this.frames.length >= TimelineRecorder.MAX_FRAMES ||\n (this.hiddenSince && performance.now() - this.hiddenSince > 5000)\n ) {\n this.recording = false\n this.autoStopped = true\n this.onAutoStop?.()\n return\n }\n\n const anims = document.getAnimations()\n const frameAnims: FrameAnimation[] = []\n\n for (const a of anims) {\n const target = (a.effect as KeyframeEffect)?.target as HTMLElement | null\n if (!target) continue\n if (!isInBounds(target)) continue\n\n const uniqueSelector = getSelector(target)\n if (!uniqueSelector) continue\n const readableSelector = getReadableSelector(target)\n\n trackElement(target)\n\n const timing = (a.effect as KeyframeEffect)?.getTiming?.() || {}\n const duration =\n typeof timing.duration === 'number' ? timing.duration : 0\n const delay = timing.delay || 0\n const easing = timing.easing || 'linear'\n\n let name = ''\n let type = 'WebAnimation'\n if (\n a.constructor.name === 'CSSTransition' ||\n (a as any).transitionProperty\n ) {\n name = (a as any).transitionProperty || ''\n type = 'CSSTransition'\n } else if (\n a.constructor.name === 'CSSAnimation' ||\n (a as any).animationName\n ) {\n name = (a as any).animationName || ''\n type = 'CSSAnimation'\n }\n\n const id = type + ':' + name + ':' + uniqueSelector\n\n if (!this.animations.has(id)) {\n const keyframes = (a.effect as KeyframeEffect)?.getKeyframes?.() || []\n let source: string | null = null\n\n if (type === 'CSSAnimation' && keyframes.length > 0) {\n const kfLines = keyframes\n .map((kf) => {\n const offset = Math.round((kf.offset ?? 0) * 100) + '%'\n const props = Object.entries(kf)\n .filter(\n ([k]) =>\n !['offset', 'easing', 'composite', 'computedOffset'].includes(k),\n )\n .map(\n ([k, v]) =>\n k.replace(/([A-Z])/g, '-$1').toLowerCase() + ': ' + v,\n )\n .join('; ')\n return ' ' + offset + ' { ' + props + ' }'\n })\n .join('\\n')\n source =\n '@keyframes ' + (name || 'anonymous') + ' {\\n' + kfLines + '\\n}'\n } else if (type === 'CSSTransition') {\n source = 'transition: ' + name + ' ' + duration + 'ms ' + easing\n }\n\n // Resolve CSS custom properties used in transitions\n const resolvedVars: Record<string, string> = {}\n try {\n const cs = getComputedStyle(target)\n const style = target.getAttribute('style') || ''\n const allRules: string[] = []\n for (const sheet of document.styleSheets) {\n try {\n for (const rule of sheet.cssRules) {\n if (\n (rule as CSSStyleRule).selectorText &&\n target.matches((rule as CSSStyleRule).selectorText)\n ) {\n allRules.push(rule.cssText)\n }\n }\n } catch (_) {\n // Cross-origin stylesheet — skip\n }\n }\n const allCssText = allRules.join(' ') + ' ' + style\n const varRegex = /var\\(\\s*(--[a-zA-Z0-9-]+)/g\n let varMatch: RegExpExecArray | null\n while ((varMatch = varRegex.exec(allCssText)) !== null) {\n const varName = varMatch[1]\n const resolved = cs.getPropertyValue(varName).trim()\n if (resolved) {\n resolvedVars[varName] = resolved\n }\n }\n } catch (_) {\n // Non-critical\n }\n\n // Diff expected vs actual transition timing\n let conflicts: string[] | null = null\n if (type === 'CSSTransition') {\n try {\n const cs = getComputedStyle(target)\n\n const tProps = cssSplit(cs.transitionProperty)\n const tDurations = cssSplit(cs.transitionDuration).map(\n (s) => parseFloat(s) * 1000,\n )\n const tEasings = cssSplit(cs.transitionTimingFunction)\n const tDelays = cssSplit(cs.transitionDelay).map(\n (s) => parseFloat(s) * 1000,\n )\n\n let idx = tProps.indexOf(name)\n if (idx === -1 && tProps.includes('all'))\n idx = tProps.indexOf('all')\n\n if (idx >= 0) {\n const declaredDuration =\n tDurations[idx % tDurations.length] || 0\n const declaredEasing =\n tEasings[idx % tEasings.length] || 'ease'\n const declaredDelay = tDelays[idx % tDelays.length] || 0\n\n const diffs: string[] = []\n if (Math.abs(declaredDuration - duration) > 1) {\n diffs.push(\n 'duration: declared ' +\n declaredDuration +\n 'ms, actual ' +\n duration +\n 'ms',\n )\n }\n if (declaredEasing !== easing) {\n const normDeclared = declaredEasing.replace(/\\s/g, '')\n const normActual = easing.replace(/\\s/g, '')\n if (normDeclared !== normActual) {\n diffs.push(\n 'easing: declared ' +\n declaredEasing +\n ', actual ' +\n easing,\n )\n }\n }\n if (Math.abs(declaredDelay - delay) > 1) {\n diffs.push(\n 'delay: declared ' +\n declaredDelay +\n 'ms, actual ' +\n delay +\n 'ms',\n )\n }\n if (diffs.length > 0) {\n conflicts = diffs\n }\n }\n } catch (_) {\n // Non-critical\n }\n }\n\n this.animations.set(id, {\n id,\n name,\n selector: readableSelector,\n elementLabel: getElementLabel(target),\n duration,\n delay,\n easing,\n type,\n source,\n resolvedVars:\n Object.keys(resolvedVars).length > 0 ? resolvedVars : null,\n conflicts,\n })\n }\n\n // Capture per-frame property values\n const keyframes = (a.effect as KeyframeEffect)?.getKeyframes?.() || []\n const animatedProps = new Set<string>()\n for (const kf of keyframes) {\n for (const key of Object.keys(kf)) {\n if (\n !['offset', 'easing', 'composite', 'computedOffset'].includes(key)\n ) {\n animatedProps.add(key)\n }\n }\n }\n\n const computedStyle = getComputedStyle(target)\n const properties: PropertySnapshot[] = []\n for (const prop of animatedProps) {\n const kebab = prop.replace(/([A-Z])/g, '-$1').toLowerCase()\n const value = computedStyle.getPropertyValue(kebab) || ''\n if (value) {\n const from = (keyframes[0] as any)?.[prop] || null\n const to =\n (keyframes[keyframes.length - 1] as any)?.[prop] || null\n properties.push({ property: kebab, value, from, to })\n }\n }\n\n const currentTime = (a.currentTime as number) ?? 0\n const progress =\n duration > 0\n ? Math.max(0, Math.min(1, currentTime / duration))\n : 0\n frameAnims.push({ animationId: id, currentTime, progress, properties })\n }\n\n // Phase 2: Detect JS-driven animations (rAF, Framer Motion springs, etc.)\n // Compare inline style properties between frames for tracked elements\n // that don't have a corresponding WAAPI animation\n const waapiAnimatedIds = new Set<string>()\n for (const fa of frameAnims) {\n const parts = fa.animationId.split(':')\n waapiAnimatedIds.add(parts[parts.length - 1])\n }\n\n const JS_TRACK_PROPS = ['transform', 'opacity', 'left', 'top', 'right', 'bottom', 'background']\n // Also track which properties are already covered by WAAPI per element\n const waapiAnimatedProps = new Map<string, Set<string>>()\n for (const fa of frameAnims) {\n const parts = fa.animationId.split(':')\n const elKey = parts[parts.length - 1]\n if (!waapiAnimatedProps.has(elKey)) waapiAnimatedProps.set(elKey, new Set())\n const propName = parts[1] // type:propName:selector\n if (propName) waapiAnimatedProps.get(elKey)!.add(propName)\n }\n\n for (const [elId, el] of this.elements) {\n if (!el.isConnected) continue\n const hasWaapi = waapiAnimatedIds.has(elId)\n const waapiProps = waapiAnimatedProps.get(elId)\n\n const currentInline: Record<string, string> = {}\n let hasAnyInline = false\n for (const prop of JS_TRACK_PROPS) {\n const camel = prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase())\n const val = (el.style as any)[camel]\n if (val) {\n currentInline[prop] = val\n hasAnyInline = true\n }\n }\n if (!hasAnyInline) {\n this.prevInlineStyles.set(elId, currentInline)\n continue\n }\n\n const prevInline = this.prevInlineStyles.get(elId) || {}\n this.prevInlineStyles.set(elId, currentInline)\n\n for (const p of JS_TRACK_PROPS) {\n const cur = currentInline[p] || ''\n const prev = prevInline[p] || ''\n // Skip if this property is already tracked via WAAPI on this element\n const propCoveredByWaapi = waapiProps?.has(p) || waapiProps?.has(p.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase()))\n if (cur && cur !== prev && !propCoveredByWaapi) {\n const jsId = 'JSAnimation:' + p + ':' + elId\n\n // Track how many frames this property has been changing\n this.jsAnimChangeCount.set(jsId, (this.jsAnimChangeCount.get(jsId) || 0) + 1)\n\n if (!this.jsAnimStartTimes.has(jsId)) {\n this.jsAnimStartTimes.set(jsId, time)\n this.jsAnimFromValues.set(jsId, prev || cur)\n }\n this.jsAnimLastSeen.set(jsId, time)\n\n // Only register as animation after 3+ frames of continuous change\n // (single frame changes are React state toggles, not animations)\n if (this.jsAnimChangeCount.get(jsId)! < 3) continue\n\n if (!this.animations.has(jsId)) {\n const readableSel = getReadableSelector(el)\n this.animations.set(jsId, {\n id: jsId,\n name: p,\n selector: readableSel,\n elementLabel: getElementLabel(el),\n duration: 0,\n delay: 0,\n easing: 'JS-driven',\n type: 'JSAnimation',\n source: 'Detected: inline style animation (JS library or requestAnimationFrame)',\n resolvedVars: null,\n conflicts: null,\n })\n }\n\n // Update duration as animation progresses\n const startT = this.jsAnimStartTimes.get(jsId)!\n const anim = this.animations.get(jsId)!\n anim.duration = time - startT\n\n const fromVal = this.jsAnimFromValues.get(jsId) || ''\n const elapsed = time - startT\n const estimatedDuration = Math.max(anim.duration, 300)\n const prog = Math.min(1, elapsed / estimatedDuration)\n frameAnims.push({\n animationId: jsId,\n currentTime: elapsed,\n progress: prog,\n properties: [{\n property: p,\n value: cur,\n from: fromVal,\n to: cur\n }]\n })\n }\n }\n }\n\n // Snapshot computed styles, attributes, and inline styles for all tracked elements\n const elementSnapshots: Record<string, ElementSnapshot> = {}\n for (const [sel, el] of this.elements) {\n if (!el.isConnected) continue\n const cs = getComputedStyle(el)\n const snap: ElementSnapshot = { __styles: {}, __attrs: {} }\n for (const prop of SNAPSHOT_PROPS) {\n snap.__styles[prop] = cs.getPropertyValue(prop)\n }\n for (const attr of SNAPSHOT_ATTRS) {\n if (attr === 'checked') {\n snap.__attrs[attr] = (el as HTMLInputElement).checked\n ? 'true'\n : null\n } else if (attr === 'class') {\n snap.__attrs[attr] = el.className\n } else if (attr === 'style') {\n snap.__attrs[attr] = el.getAttribute('style') || ''\n } else if (attr === 'value') {\n snap.__attrs[attr] =\n (el as HTMLInputElement).value !== undefined\n ? String((el as HTMLInputElement).value)\n : null\n } else {\n snap.__attrs[attr] = el.getAttribute(attr)\n }\n }\n // Pseudo-element opacity\n try {\n snap.__afterOpacity = getComputedStyle(el, '::after').getPropertyValue(\n 'opacity',\n )\n snap.__beforeOpacity = getComputedStyle(\n el,\n '::before',\n ).getPropertyValue('opacity')\n } catch (_) {\n // Non-critical\n }\n elementSnapshots[sel] = snap\n }\n\n // Check for hidden portals whose display was 'none' but are still\n // tracked — mark them as visible if they were un-hidden by React\n for (const [id, portal] of this.activePortals) {\n if (\n portal.element?.isConnected &&\n !portal.element.hasAttribute('data-lapse-portal-hidden')\n ) {\n this.currentPortalIds.add(id)\n }\n }\n\n this.frames.push({\n time,\n animations: frameAnims,\n elementSnapshots,\n activePortalIds: [...this.currentPortalIds],\n hoveredSels: [...this.currentHoverEls],\n focusSel: this.currentFocusSel,\n pointer: { ...this.currentPointer },\n scrollPositions: {},\n })\n\n this._raf(captureFrame)\n }\n\n this._raf(captureFrame)\n }\n\n // =========================================================================\n // stopRecording\n // =========================================================================\n\n stopRecording(): TimelineCapture {\n if (!this.recording) {\n return {\n startTime: 0,\n endTime: 0,\n duration: 0,\n animations: [],\n frames: [],\n boundingBox: null,\n }\n }\n\n this.recording = false\n\n // ------------------------------------------------------------------\n // Restore patched prototypes\n // ------------------------------------------------------------------\n\n if (this._removeChild) Node.prototype.removeChild = this._removeChild\n if (this._remove) Element.prototype.remove = this._remove\n if (this._elementAnimate) Element.prototype.animate = this._elementAnimate\n\n // ------------------------------------------------------------------\n // Disconnect observers & remove event listeners\n // ------------------------------------------------------------------\n\n this.attrObserver?.disconnect()\n this.portalObserver?.disconnect()\n this.exitObserver?.disconnect()\n if (this.onVisibilityChange) {\n document.removeEventListener('visibilitychange', this.onVisibilityChange)\n this.onVisibilityChange = null\n }\n\n if (this.onMouseOver)\n document.removeEventListener('mouseover', this.onMouseOver, true)\n if (this.onMouseOut)\n document.removeEventListener('mouseout', this.onMouseOut, true)\n if (this.onFocusIn)\n document.removeEventListener('focusin', this.onFocusIn, true)\n if (this.onFocusOut)\n document.removeEventListener('focusout', this.onFocusOut, true)\n if (this.onPointerMove)\n document.removeEventListener('pointermove', this.onPointerMove, true)\n if (this.onPointerDown)\n document.removeEventListener('pointerdown', this.onPointerDown, true)\n if (this.onPointerUp)\n document.removeEventListener('pointerup', this.onPointerUp, true)\n\n // ------------------------------------------------------------------\n // Cancel all running animations\n // ------------------------------------------------------------------\n\n try {\n for (const anim of document.getAnimations()) {\n anim.cancel()\n }\n } catch (_) {\n // Non-critical\n }\n\n // ------------------------------------------------------------------\n // Freeze requestAnimationFrame — prevent the page from running new\n // rAF callbacks that would fight our frozen visual state.\n // ------------------------------------------------------------------\n\n window.requestAnimationFrame = () => 0\n\n // ------------------------------------------------------------------\n // Inject no-transitions style\n // ------------------------------------------------------------------\n\n const noTransitions = document.createElement('style')\n noTransitions.id = '__lapse-no-transitions'\n noTransitions.textContent =\n '*, *::before, *::after { transition: none !important; animation: none !important; }'\n document.head.appendChild(noTransitions)\n this.noTransitionsEl = noTransitions\n\n // ------------------------------------------------------------------\n // Add interaction blocker overlay\n // ------------------------------------------------------------------\n\n const blocker = document.createElement('div')\n blocker.id = '__lapse-scrub-blocker'\n blocker.style.cssText =\n 'position:fixed;inset:0;z-index:999999;cursor:not-allowed;background:transparent;'\n blocker.title = 'Clear the timeline to interact with the page'\n document.body.appendChild(blocker)\n this.blockerEl = blocker\n\n // ------------------------------------------------------------------\n // Clone :hover / :focus CSS rules\n // ------------------------------------------------------------------\n\n try {\n const lapseStyle = document.createElement('style')\n lapseStyle.id = '__lapse-state-rules'\n\n let allCss = ''\n for (const style of document.querySelectorAll('style')) {\n if (style.id === '__lapse-state-rules') continue\n allCss += style.textContent + '\\n'\n }\n\n // Note: fetch for external stylesheets is async. In the Electron version\n // this ran in an async IIFE. Here we gather what we can synchronously\n // (inline <style>, and CSSOM rules) which covers the vast majority of\n // cases. External stylesheet text is fetched below but we also walk\n // sheet.cssRules as a synchronous fallback.\n for (const sheet of document.styleSheets) {\n try {\n function walk(rules: CSSRuleList) {\n for (const rule of rules) {\n if ((rule as CSSGroupingRule).cssRules) {\n walk((rule as CSSGroupingRule).cssRules)\n continue\n }\n const t = rule.cssText\n if (t && (t.includes(':hover') || t.includes(':focus'))) {\n allCss += t + '\\n'\n }\n }\n }\n walk(sheet.cssRules)\n } catch (_) {\n // Cross-origin stylesheet — skip\n }\n }\n\n // Extract and clone :hover / :focus rules\n const stateRegex =\n /([^{}]*(?::hover|:focus-visible|:focus-within|:focus(?!-))[^{}]*)\\{([^{}]*)\\}/g\n let match: RegExpExecArray | null\n while ((match = stateRegex.exec(allCss)) !== null) {\n const selector = match[1].trim()\n const body = match[2].trim()\n if (!body) continue\n\n const newBody = body.replace(\n /([^;:]+):\\s*([^;]+)(;|$)/g,\n (m, prop: string, val: string, end: string) => {\n if (val.includes('!important')) return m\n return prop + ': ' + val.trim() + ' !important' + end\n },\n )\n\n // Clone hover rules\n if (selector.includes(':hover')) {\n lapseStyle.textContent +=\n selector.replace(/:hover/g, '[data-lapse-hover]') +\n ' { ' +\n newBody +\n ' }\\n'\n }\n // Clone focus rules\n if (selector.includes(':focus-visible')) {\n lapseStyle.textContent +=\n selector.replace(/:focus-visible/g, '[data-lapse-focus]') +\n ' { ' +\n newBody +\n ' }\\n'\n } else if (selector.includes(':focus-within')) {\n lapseStyle.textContent +=\n selector.replace(\n /:focus-within/g,\n ':has([data-lapse-focus])',\n ) +\n ' { ' +\n newBody +\n ' }\\n'\n } else if (selector.includes(':focus')) {\n lapseStyle.textContent +=\n selector.replace(/:focus(?!-)/g, '[data-lapse-focus]') +\n ' { ' +\n newBody +\n ' }\\n'\n }\n }\n\n document.head.appendChild(lapseStyle)\n this.lapseStyleEl = lapseStyle\n } catch (_) {\n // Non-critical\n }\n\n // ------------------------------------------------------------------\n // Apply frame 0 snapshot to reset visual state (safe props only)\n // ------------------------------------------------------------------\n\n if (this.frames.length > 0) {\n const frame0 = this.frames[0]\n if (frame0.elementSnapshots) {\n for (const [sel, snap] of Object.entries(frame0.elementSnapshots)) {\n const el = this.elements.get(sel)\n if (!el || !el.isConnected) continue\n if (snap.__styles) {\n for (const [prop, value] of Object.entries(snap.__styles)) {\n if (SAFE_PROPS_SET.has(prop)) {\n el.style.setProperty(prop, value, 'important')\n }\n }\n }\n if (snap.__attrs) {\n for (const [attr, value] of Object.entries(snap.__attrs)) {\n if (attr === 'checked') {\n ;(el as HTMLInputElement).checked = value === 'true'\n } else if (attr === 'class' && value != null) {\n el.className = value\n } else if (attr === 'style') {\n // Skip — handled by __styles\n } else if (attr === 'value' && value != null) {\n ;(el as HTMLInputElement).value = value\n } else if (value == null) {\n el.removeAttribute(attr)\n } else {\n el.setAttribute(attr, value)\n }\n }\n }\n }\n }\n }\n\n // ------------------------------------------------------------------\n // Build and return the capture\n // ------------------------------------------------------------------\n\n const duration =\n this.frames.length > 0\n ? this.frames[this.frames.length - 1].time\n : 0\n\n const capture: TimelineCapture = {\n startTime: this.startTime,\n endTime: performance.now(),\n duration,\n animations: Array.from(this.animations.values()),\n frames: this.frames,\n boundingBox: this.boundingBox,\n }\n\n return capture\n }\n}\n","import type { FrameSnapshot, ElementSnapshot } from './types'\n\n/**\n * Represents a WAAPI Animation intercepted during recording.\n * The recorder monkey-patches Element.prototype.animate to capture these.\n */\nexport interface InterceptedAnimation {\n animation: Animation\n target: Element\n}\n\n/**\n * State handed from the recorder after stopRecording().\n * This is everything the scrubber needs to replay frames.\n */\nexport interface ScrubberState {\n /** Selector string -> live DOM element */\n elements: Map<string, HTMLElement>\n /** Captured frame snapshots from the recording */\n frames: FrameSnapshot[]\n /** All portal IDs ever captured (for show/hide management) */\n capturedPortals: Set<string>\n /** WAAPI animations intercepted via Element.prototype.animate patch */\n interceptedAnimations: InterceptedAnimation[]\n /** Set of CSS properties that are safe (visual-only, no layout side-effects) */\n SAFE_PROPS_SET: Set<string>\n}\n\n/**\n * Timeline scrubber — applies captured frame snapshots to the live DOM.\n *\n * Ported from the inline JS that the Electron version injected via\n * executeJavaScript() in timeline-controller.ts (seekTo / releaseAnimations).\n */\nexport class TimelineScrubber {\n private elements: Map<string, HTMLElement>\n private frames: FrameSnapshot[]\n private capturedPortals: Set<string>\n private interceptedAnimations: InterceptedAnimation[]\n private SAFE_PROPS_SET: Set<string>\n\n /** Saved originals for restore on release */\n private _originalAnimate: typeof Element.prototype.animate | null = null\n private _originalRaf: typeof requestAnimationFrame | null = null\n private _originalRemoveChild: typeof Node.prototype.removeChild | null = null\n private _originalRemove: typeof Element.prototype.remove | null = null\n\n constructor(state: ScrubberState) {\n this.elements = state.elements\n this.frames = state.frames\n this.capturedPortals = state.capturedPortals\n this.interceptedAnimations = state.interceptedAnimations\n this.SAFE_PROPS_SET = state.SAFE_PROPS_SET\n\n // Stash originals that the recorder may have patched\n this._originalAnimate = (window as any).__LAPSE_ORIGINAL_ANIMATE__ ?? null\n this._originalRaf = (window as any).__LAPSE_ORIGINAL_RAF__ ?? null\n this._originalRemoveChild = (window as any).__LAPSE_TIMELINE__?._removeChild ?? null\n this._originalRemove = (window as any).__LAPSE_TIMELINE__?._remove ?? null\n }\n\n // ---------------------------------------------------------------------------\n // Selector helper — mirrors the recorder's getSelector so we can look up\n // elements by the same key the recorder used in frame.animations[].animationId\n // ---------------------------------------------------------------------------\n\n private getSelector(el: Element): string | null {\n if (!el || !(el as HTMLElement).tagName) return null\n const parts: string[] = []\n let current: Element | null = el\n for (let i = 0; i < 5 && current && current.tagName && current.tagName !== 'HTML'; i++) {\n const tag = current.tagName.toLowerCase()\n const parent: Element | null = current.parentElement\n if (parent) {\n const siblings = Array.from(parent.children)\n const idx = siblings.indexOf(current) + 1\n parts.unshift(`${tag}:nth-child(${idx})`)\n } else {\n parts.unshift(tag)\n }\n current = parent\n }\n return parts.join(' > ')\n }\n\n // ---------------------------------------------------------------------------\n // seekTo — scrub the DOM to match a specific timestamp\n // ---------------------------------------------------------------------------\n\n seekTo(timeMs: number): void {\n if (!this.frames.length) return\n\n // Binary search for closest frame\n let lo = 0\n let hi = this.frames.length - 1\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (this.frames[mid].time < timeMs) lo = mid + 1\n else hi = mid\n }\n const frame = this.frames[lo]\n if (!frame || !frame.elementSnapshots) return\n\n // -----------------------------------------------------------------------\n // Clear state markers\n // -----------------------------------------------------------------------\n document.querySelectorAll('[data-lapse-hover]').forEach((el) => {\n el.removeAttribute('data-lapse-hover')\n })\n document.querySelectorAll('[data-lapse-focus]').forEach((el) => {\n el.removeAttribute('data-lapse-focus')\n })\n\n // -----------------------------------------------------------------------\n // Manage portals — show/hide original elements kept in DOM via removal\n // intercept. All portals get pointer-events:none during scrub.\n // -----------------------------------------------------------------------\n const activeIds = new Set(frame.activePortalIds || [])\n for (const id of this.capturedPortals) {\n const portalEl = document.querySelector(\n `[data-lapse-portal-id=\"${id}\"]`\n ) as HTMLElement | null\n if (!portalEl) continue\n if (activeIds.has(id)) {\n portalEl.style.removeProperty('display')\n portalEl.removeAttribute('data-lapse-portal-hidden')\n } else {\n portalEl.style.setProperty('display', 'none', 'important')\n }\n }\n\n // -----------------------------------------------------------------------\n // Apply hover markers\n // -----------------------------------------------------------------------\n const hoveredSels = frame.hoveredSels || []\n for (const sel of hoveredSels) {\n const el = this.elements.get(sel)\n if (el && el.isConnected) el.setAttribute('data-lapse-hover', '')\n }\n\n // -----------------------------------------------------------------------\n // Apply focus marker (+ ancestors for :focus-within)\n // -----------------------------------------------------------------------\n if (frame.focusSel) {\n const focusEl = this.elements.get(frame.focusSel)\n if (focusEl && focusEl.isConnected) {\n focusEl.setAttribute('data-lapse-focus', '')\n let parent = focusEl.parentElement\n while (parent && parent !== document.body) {\n parent.setAttribute('data-lapse-focus', '')\n parent = parent.parentElement\n }\n }\n }\n\n // -----------------------------------------------------------------------\n // Cancel intercepted WAAPI animations — pause + seek to match frame time\n // -----------------------------------------------------------------------\n for (const entry of this.interceptedAnimations) {\n try {\n const anim = entry.animation\n if (anim.playState !== 'finished') {\n anim.pause()\n }\n anim.currentTime = timeMs\n } catch {\n // Animation may have been garbage collected\n }\n }\n\n // -----------------------------------------------------------------------\n // Apply element snapshots\n // -----------------------------------------------------------------------\n for (const [sel, snap] of Object.entries(frame.elementSnapshots)) {\n const el = this.elements.get(sel)\n if (!el || !el.isConnected) continue\n if (el.closest?.('[data-lapse-panel]')) continue\n\n // Check if this element has any active animation at this frame\n const hasAnimation = (frame.animations || []).some(\n (a) =>\n a.animationId.endsWith(':' + sel) ||\n a.animationId.includes(':' + sel.split(' > ').pop())\n )\n\n // Apply computed styles — visual (safe) props always,\n // layout props only if the element has active animations\n const snapTyped = snap as ElementSnapshot\n if (snapTyped.__styles) {\n for (const [prop, value] of Object.entries(snapTyped.__styles)) {\n if (this.SAFE_PROPS_SET.has(prop) || hasAnimation) {\n el.style.setProperty(prop, value, 'important')\n }\n }\n }\n\n // Apply non-style attributes (class, data-*, aria-*, checked, etc.)\n if (snapTyped.__attrs) {\n for (const [attr, value] of Object.entries(snapTyped.__attrs)) {\n if (attr === 'checked') {\n ;(el as HTMLInputElement).checked = value === 'true'\n } else if (attr === 'class') {\n if (value != null) el.className = value\n } else if (attr === 'style') {\n // For elements with React-managed inline styles (segmented control pill,\n // sliders), apply the captured inline style, then re-apply transition:none\n // and our computed overrides on top\n if (value) {\n el.setAttribute('style', value)\n el.style.transition = 'none'\n // Re-apply computed style overrides on top\n if (snapTyped.__styles) {\n for (const [prop, val] of Object.entries(snapTyped.__styles)) {\n el.style.setProperty(prop, val, 'important')\n }\n }\n }\n } else if (attr === 'value') {\n if (value != null) (el as HTMLInputElement).value = value\n } else if (value == null) {\n el.removeAttribute(attr)\n } else {\n el.setAttribute(attr, value)\n }\n }\n }\n }\n\n // -----------------------------------------------------------------------\n // Override stale snapshot values with accurate WAAPI mid-transition data.\n // frame.animations[].properties have correct mid-transition values from\n // getComputedStyle on getAnimations() targets (which ARE mid-transition).\n // The element snapshots may have stale base values for some elements.\n // -----------------------------------------------------------------------\n for (const anim of frame.animations || []) {\n const firstColon = anim.animationId.indexOf(':')\n const secondColon = anim.animationId.indexOf(':', firstColon + 1)\n const animSel =\n secondColon >= 0 ? anim.animationId.substring(secondColon + 1) : ''\n const animEl = this.elements.get(animSel)\n if (!animEl || !animEl.isConnected) continue\n for (const prop of anim.properties || []) {\n if (prop.value) {\n animEl.style.setProperty(prop.property, prop.value, 'important')\n }\n }\n }\n\n // -----------------------------------------------------------------------\n // Clean up indicator overrides on checkboxes/radios.\n // For indicator elements without active animations at this frame,\n // remove stale inline overrides so CSS cascade from data-state takes effect.\n // -----------------------------------------------------------------------\n const animatedSels = new Set<string>()\n for (const anim of frame.animations || []) {\n const fc = anim.animationId.indexOf(':')\n const sc = anim.animationId.indexOf(':', fc + 1)\n if (sc >= 0) animatedSels.add(anim.animationId.substring(sc + 1))\n }\n document\n .querySelectorAll('.checkbox-indicator, .radio-indicator')\n .forEach((rawEl) => {\n const el = rawEl as HTMLElement\n const sel = this.getSelector(el)\n if (sel && !animatedSels.has(sel)) {\n el.style.removeProperty('opacity')\n el.style.removeProperty('transform')\n el.style.removeProperty('filter')\n el.style.removeProperty('stroke-dashoffset')\n }\n })\n }\n\n // ---------------------------------------------------------------------------\n // release — tear down all scrub state and restore the page to normal\n // ---------------------------------------------------------------------------\n\n release(): void {\n // Cancel intercepted WAAPI animations\n for (const entry of this.interceptedAnimations) {\n try {\n entry.animation.cancel()\n } catch {\n // Already finished or GC'd\n }\n }\n this.interceptedAnimations.length = 0\n\n // Restore Element.prototype.animate if we patched it\n if (this._originalAnimate) {\n Element.prototype.animate = this._originalAnimate\n this._originalAnimate = null\n delete (window as any).__LAPSE_ORIGINAL_ANIMATE__\n }\n\n // Restore requestAnimationFrame if we patched it\n if (this._originalRaf) {\n window.requestAnimationFrame = this._originalRaf\n this._originalRaf = null\n delete (window as any).__LAPSE_ORIGINAL_RAF__\n }\n\n // Remove global transition/animation override style\n const tl = (window as any).__LAPSE_TIMELINE__\n if (tl?.noTransitionsEl) {\n tl.noTransitionsEl.remove()\n }\n const noTrans = document.getElementById('__lapse-no-transitions')\n if (noTrans) noTrans.remove()\n\n // Remove interaction blocker\n const blocker = document.getElementById('__lapse-scrub-blocker')\n if (blocker) blocker.remove()\n if (tl?.blockerEl) tl.blockerEl.remove()\n\n // Remove cloned state rules style (hover/focus rule clones)\n const stateRules = document.getElementById('__lapse-state-rules')\n if (stateRules) stateRules.remove()\n if (tl?.lapseStyleEl) tl.lapseStyleEl.remove()\n\n // Restore original DOM removal methods\n if (this._originalRemoveChild) {\n Node.prototype.removeChild = this._originalRemoveChild\n this._originalRemoveChild = null\n } else if (tl?._removeChild) {\n Node.prototype.removeChild = tl._removeChild\n }\n\n if (this._originalRemove) {\n Element.prototype.remove = this._originalRemove\n this._originalRemove = null\n } else if (tl?._remove) {\n Element.prototype.remove = tl._remove\n }\n\n // Remove exit-captured elements (re-inserted hidden during recording)\n document.querySelectorAll('[data-lapse-exit-captured]').forEach((el) => {\n el.remove()\n })\n\n // Clean up data-lapse-* attributes from all elements\n document.querySelectorAll('[data-lapse-id]').forEach((el) => {\n el.removeAttribute('data-lapse-id')\n })\n document.querySelectorAll('[data-lapse-hover]').forEach((el) => {\n el.removeAttribute('data-lapse-hover')\n })\n document.querySelectorAll('[data-lapse-focus]').forEach((el) => {\n el.removeAttribute('data-lapse-focus')\n })\n document.querySelectorAll('[data-lapse-portal-id]').forEach((el) => {\n el.removeAttribute('data-lapse-portal-id')\n el.removeAttribute('data-lapse-portal-hidden')\n })\n\n // Clear the global timeline object\n delete (window as any).__LAPSE_TIMELINE__\n\n // Clear local references\n this.elements.clear()\n this.frames.length = 0\n this.capturedPortals.clear()\n }\n}\n","import type {\n AnimationInfo,\n ExportFilter,\n FrameSnapshot,\n OutputDetailLevel,\n TimelineExport\n} from './types'\n\nexport function getFrameAtTime(frames: FrameSnapshot[], timeMs: number): FrameSnapshot | null {\n if (frames.length === 0) return null\n let lo = 0\n let hi = frames.length - 1\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (frames[mid].time < timeMs) lo = mid + 1\n else hi = mid\n }\n return frames[lo]\n}\n\nexport function generateExport(\n animations: AnimationInfo[],\n frames: FrameSnapshot[],\n timeMs: number,\n filter: ExportFilter = 'active'\n): TimelineExport {\n const frame = getFrameAtTime(frames, timeMs)\n const duration = frames.at(-1)?.time ?? 0\n\n const filteredAnims = animations.filter((anim) => {\n if (filter === 'all-animations') return true\n if (filter === 'active') {\n const frameAnim = frame?.animations.find((a) => a.animationId === anim.id)\n if (!frameAnim || frameAnim.progress <= 0 || frameAnim.progress >= 1) return false\n if (frameAnim.properties.length > 0) {\n const hasRealChange = frameAnim.properties.some(\n (p) => p.from && p.to && p.from !== p.to\n )\n if (!hasRealChange) return false\n }\n return true\n }\n return true\n })\n\n const animExports = filteredAnims.map((anim) => {\n // Find this animation in the current frame, or fall back to the last frame it appeared in\n let frameAnim = frame?.animations.find((a) => a.animationId === anim.id)\n let status: 'active' | 'completed' | 'upcoming' = frameAnim ? 'active' : 'completed'\n\n if (!frameAnim) {\n // Search backwards for the last frame this animation appeared in\n for (let i = frames.length - 1; i >= 0; i--) {\n if (frames[i].time > timeMs) continue\n const found = frames[i].animations.find((a) => a.animationId === anim.id)\n if (found) { frameAnim = found; break }\n }\n // If still not found, search forward (animation hasn't started yet)\n if (!frameAnim) {\n for (let i = 0; i < frames.length; i++) {\n if (frames[i].time < timeMs) continue\n const found = frames[i].animations.find((a) => a.animationId === anim.id)\n if (found) { frameAnim = found; status = 'upcoming'; break }\n }\n }\n }\n\n const progressLabel = status === 'active'\n ? `${Math.round((frameAnim?.progress ?? 0) * 100)}%`\n : status === 'completed' ? 'done' : 'upcoming'\n\n return {\n element: anim.selector,\n elementLabel: anim.elementLabel || anim.selector,\n name: anim.name || anim.type,\n type: anim.type,\n timing: `${Math.round(anim.duration)}ms ${anim.easing}${anim.delay ? ` (delay: ${Math.round(anim.delay)}ms)` : ''}`,\n progress: progressLabel,\n properties: (frameAnim?.properties ?? []).map((p) => ({\n property: p.property,\n value: p.value,\n range: p.from && p.to ? `${p.from} \\u2192 ${p.to}` : ''\n })),\n source: anim.source,\n resolvedVars: anim.resolvedVars,\n conflicts: anim.conflicts\n }\n })\n\n const hoveredElements = Array.isArray(frame?.hoveredSels)\n ? frame.hoveredSels.map(String)\n : []\n const focusedElement = frame?.focusSel ? String(frame.focusSel) : null\n\n return {\n timestamp: `${Math.round(timeMs)}ms into ${Math.round(duration)}ms recording`,\n duration: `${Math.round(duration)}ms`,\n scrubPosition: timeMs,\n hoveredElements,\n focusedElement,\n animations: animExports\n }\n}\n\nexport function formatExportForLLM(exp: TimelineExport, detail: OutputDetailLevel = 'standard'): string {\n const lines: string[] = []\n\n // Group animations by element\n const grouped = new Map<string, { label: string; selector: string; anims: typeof exp.animations }>()\n for (const anim of exp.animations) {\n const key = (anim.elementLabel || '') + '|||' + anim.element\n if (!grouped.has(key)) {\n grouped.set(key, { label: anim.elementLabel || '', selector: anim.element, anims: [] })\n }\n grouped.get(key)!.anims.push(anim)\n }\n\n // Helper: skip no-change properties\n function isRealChange(prop: { range: string }): boolean {\n if (!prop.range) return true\n const [from, to] = prop.range.split(' \\u2192 ')\n return !(from && to && from.trim() === to.trim())\n }\n\n // ── Compact ──────────────────────────────────────────────────────────\n if (detail === 'compact') {\n lines.push(`# Animation State at ${exp.timestamp}`)\n lines.push('')\n for (const [, group] of grouped) {\n const label = group.label && group.label !== group.selector\n ? `**${group.label}** \\`${group.selector}\\``\n : `\\`${group.selector}\\``\n const cssAnims = group.anims.filter((a) => a.type !== 'JSAnimation')\n const jsAnims = group.anims.filter((a) => a.type === 'JSAnimation')\n\n if (cssAnims.length > 0) {\n const props = new Set<string>()\n for (const a of cssAnims) a.properties.filter(isRealChange).forEach((p) => props.add(p.property))\n const timing = cssAnims[0]?.timing || ''\n const progress = cssAnims[0]?.progress || ''\n const progressStr = progress && progress !== 'unknown' ? ` @ ${progress}` : ''\n lines.push(`- ${label}: ${[...props].join(', ')} (${timing}${progressStr})`)\n }\n if (jsAnims.length > 0) {\n const props = new Set<string>()\n for (const a of jsAnims) a.properties.filter(isRealChange).forEach((p) => props.add(p.property))\n if (props.size > 0) lines.push(`- ${label}: ${[...props].join(', ')} (JS)`)\n }\n }\n return lines.join('\\n')\n }\n\n // ── Standard / Detailed / Forensic ───────────────────────────────────\n lines.push(`# Animation State at ${exp.timestamp}`)\n lines.push('')\n\n // Forensic: environment info\n if (detail === 'forensic') {\n lines.push('**Environment:**')\n lines.push(`- Viewport: ${window.innerWidth}\\u00d7${window.innerHeight}`)\n lines.push(`- URL: ${window.location.href}`)\n lines.push(`- User Agent: ${navigator.userAgent}`)\n lines.push(`- Timestamp: ${new Date().toISOString()}`)\n lines.push(`- Device Pixel Ratio: ${window.devicePixelRatio}`)\n lines.push('')\n }\n\n // Interaction state (standard+)\n if (exp.hoveredElements.length > 0 || exp.focusedElement) {\n lines.push('**Interaction state:**')\n if (exp.hoveredElements.length > 0) {\n const deepest = exp.hoveredElements[exp.hoveredElements.length - 1] || exp.hoveredElements[0]\n lines.push(`- Hovered: \\`${deepest}\\``)\n }\n if (exp.focusedElement) {\n lines.push(`- Focused: \\`${exp.focusedElement}\\``)\n }\n lines.push('')\n }\n\n if (exp.animations.length === 0 && exp.hoveredElements.length === 0 && !exp.focusedElement) {\n lines.push('No active animations or interactions at this position.')\n return lines.join('\\n')\n }\n\n if (exp.animations.length === 0) {\n return lines.join('\\n')\n }\n\n for (const [, group] of grouped) {\n const label = group.label && group.label !== group.selector ? `\"${group.label}\" ` : ''\n const cssAnims = group.anims.filter((a) => a.type !== 'JSAnimation')\n const jsAnims = group.anims.filter((a) => a.type === 'JSAnimation')\n\n // Collect CSS property lines\n const cssPropLines: string[] = []\n if (cssAnims.length > 0) {\n const seenProps = new Set<string>()\n for (const anim of cssAnims) {\n const progressStr = anim.progress !== 'unknown' ? ` @ ${anim.progress}` : ''\n for (const prop of anim.properties) {\n if (seenProps.has(prop.property)) continue\n if (!isRealChange(prop)) continue\n seenProps.add(prop.property)\n let line = `- \\`${prop.property}\\`: ${prop.value}`\n if (prop.range) line += ` [${prop.range}]`\n line += ` (${anim.timing}${progressStr})`\n cssPropLines.push(line)\n }\n }\n }\n\n // Collect JS property lines\n const jsPropLines: string[] = []\n if (jsAnims.length > 0) {\n const seenProps = new Set<string>()\n for (const anim of jsAnims) {\n for (const prop of anim.properties) {\n if (seenProps.has(prop.property)) continue\n if (!isRealChange(prop)) continue\n seenProps.add(prop.property)\n jsPropLines.push(`- \\`${prop.property}\\`: ${prop.value}`)\n }\n }\n }\n\n // Skip group entirely if nothing to show\n if (cssPropLines.length === 0 && jsPropLines.length === 0) continue\n\n lines.push(`## ${label}\\`${group.selector}\\``)\n lines.push('')\n\n if (cssPropLines.length > 0) {\n const transitionSet = new Set(cssAnims.map((a) => `${a.name} ${a.timing}`))\n lines.push(`Transitions: ${[...transitionSet].join(', ')}`)\n lines.push('')\n for (const line of cssPropLines) lines.push(line)\n\n if (detail === 'detailed' || detail === 'forensic') {\n const allVars: Record<string, string> = {}\n for (const anim of cssAnims) {\n if (anim.resolvedVars) Object.assign(allVars, anim.resolvedVars)\n }\n if (Object.keys(allVars).length > 0) {\n lines.push('')\n lines.push('CSS variables:')\n for (const [name, value] of Object.entries(allVars)) {\n lines.push(`- \\`${name}\\`: ${value}`)\n }\n }\n\n for (const anim of cssAnims) {\n if (anim.source) {\n lines.push('')\n lines.push('```css')\n lines.push(anim.source)\n lines.push('```')\n break\n }\n }\n }\n }\n\n if (jsPropLines.length > 0) {\n if (cssPropLines.length > 0) lines.push('')\n for (const line of jsPropLines) lines.push(line)\n }\n\n lines.push('')\n }\n\n return lines.join('\\n')\n}\n","import { TimingController } from './timing'\nimport { TimelineRecorder } from './recorder'\nimport { TimelineScrubber, type ScrubberState } from './scrubber'\nimport { generateExport, formatExportForLLM } from './export'\nimport type {\n ExportFilter,\n OutputDetailLevel,\n Rect,\n TimelineCapture,\n TimelineExport\n} from './types'\n\nexport type LapseState = 'idle' | 'recording' | 'scrubbing'\n\nexport class LapseEngine {\n private timing = new TimingController()\n private recorder = new TimelineRecorder()\n private scrubber: TimelineScrubber | null = null\n private capture: TimelineCapture | null = null\n private _state: LapseState = 'idle'\n private listeners = new Set<() => void>()\n\n get state(): LapseState {\n return this._state\n }\n\n getCapture(): TimelineCapture | null {\n return this.capture\n }\n\n // -- Speed control --------------------------------------------------------\n\n setSpeed(speed: number): void {\n this.timing.setSpeed(speed)\n }\n\n getSpeed(): number {\n return this.timing.getSpeed()\n }\n\n // -- Timeline recording ---------------------------------------------------\n\n startRecording(boundingBox?: Rect | null): void {\n if (this._state !== 'idle') return\n this.timing.install()\n this.recorder.onAutoStop = () => this.stopRecording()\n this.recorder.startRecording(boundingBox)\n this._state = 'recording'\n this.notify()\n }\n\n stopRecording(): TimelineCapture {\n if (this._state !== 'recording') {\n return {\n startTime: 0, endTime: 0, duration: 0,\n animations: [], frames: [], boundingBox: null\n }\n }\n\n const capture = this.recorder.stopRecording()\n this.capture = capture\n\n // Create scrubber with recorder's state\n const scrubberState: ScrubberState = {\n elements: this.recorder.elements,\n frames: capture.frames,\n capturedPortals: this.recorder.capturedPortalIds,\n interceptedAnimations: this.recorder.interceptedAnimations,\n SAFE_PROPS_SET: this.recorder.SAFE_PROPS_SET\n }\n this.scrubber = new TimelineScrubber(scrubberState)\n\n this._state = 'scrubbing'\n this.notify()\n return capture\n }\n\n // -- Scrubbing ------------------------------------------------------------\n\n seekTo(timeMs: number): void {\n this.scrubber?.seekTo(timeMs)\n }\n\n release(): void {\n this.scrubber?.release()\n this.scrubber = null\n this.capture = null\n this._state = 'idle'\n this.notify()\n }\n\n // -- Export ---------------------------------------------------------------\n\n generateExport(timeMs: number, filter: ExportFilter = 'active'): TimelineExport | null {\n if (!this.capture) return null\n return generateExport(\n this.capture.animations,\n this.capture.frames,\n timeMs,\n filter\n )\n }\n\n exportForLLM(timeMs: number, filter: ExportFilter = 'active', detail: OutputDetailLevel = 'standard'): string {\n const exp = this.generateExport(timeMs, filter)\n if (!exp) return ''\n return formatExportForLLM(exp, detail)\n }\n\n // -- State subscription ---------------------------------------------------\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener()\n }\n }\n\n // -- Cleanup --------------------------------------------------------------\n\n destroy(): void {\n this.scrubber?.release()\n this.scrubber = null\n this.capture = null\n this.timing.destroy()\n this._state = 'idle'\n }\n}\n"],"mappings":"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","names":["keyframes","walk"]}
|