mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 12:54:29 +00:00
Fixes #473. ## Problem The HyperFrames skill now tells agents to add deterministic `tl.set()` hard-kills after elements fade out at beat / scene boundaries, but the linter did not enforce that rule outside the narrow caption-specific check. That made the rule easy for sub-agents to ignore: an element could fade to `opacity: 0` exactly as the next clip starts, with no explicit hidden-state set at the boundary. During non-linear seeking or frame capture, that leaves the final visibility state dependent on tween interpolation instead of an authored deterministic kill. ## What this fixes This PR adds a generalized GSAP lint warning for scene-boundary exits: - detects GSAP `to` / `fromTo` exit tweens that end at or near a clip `data-start` boundary - treats `opacity: 0`, `autoAlpha: 0`, `visibility: "hidden"`, and `display: "none"` as hidden exit states - requires a matching same-selector `tl.set(...)` hidden state at the same boundary - scopes clip-boundary matching to the timeline's registered composition so sub-composition exits do not match unrelated root boundaries - reports `gsap_exit_missing_hard_kill` with the selector, boundary time, source snippet, and a fix hint that preserves the authored hidden property when possible - keeps valid compositions quiet when the boundary hard-kill already exists ## Why Clip boundaries are the exact points where rendered frames are most sensitive to stale DOM state. A fade-out tween describes a transition, but it does not give the linter or the authoring model an explicit deterministic state to land on when seeking around the boundary. The existing caption rule proved the class of bug was worth catching, but it only applied to caption-loop patterns. The issue in #473 is broader: any element inside a timed composition can exit at a scene boundary and need the same deterministic cleanup. ## Root cause The GSAP lint rule parser already calculated tween windows and clip metadata existed in the lint context, but no rule connected those two facts: - clip `data-start` values were not used as scene-boundary checkpoints for GSAP exits - parsed GSAP windows tracked property names, but not enough property values to tell whether a tween ended in a hidden state - hard-kill detection only existed as a caption-specific regex, so normal scene elements were missed This PR extends the existing GSAP window metadata with parsed property values, then checks hidden-state exits against same-composition clip start boundaries and same-selector `tl.set` calls. ## Verification ### Local checks - `bun run --filter @hyperframes/core test src/lint/rules/gsap.test.ts` - `bunx oxlint packages/core/src/lint/rules/gsap.ts packages/core/src/lint/rules/gsap.test.ts` - `bunx oxfmt --check packages/core/src/lint/rules/gsap.ts packages/core/src/lint/rules/gsap.test.ts` - `bun run --filter @hyperframes/core typecheck` - `bun run --filter @hyperframes/core test` - `bun run --filter @hyperframes/core build` ### CLI verification Verified against local fixtures where `#headline` exits at the next clip boundary without a hard kill: - opacity fixture reports `gsap_exit_missing_hard_kill` for `#headline` at `3.00s` - autoAlpha fixture reports the same warning and suggests `tl.set("#headline", { autoAlpha: 0 }, 3.00)` - sub-composition regression test confirms a `sub` timeline exit no longer matches an unrelated root composition boundary ### Browser verification Verified the Studio lint flow with `agent-browser` against the autoAlpha fixture: - opened Studio at `http://127.0.0.1:43174/#project/issue-473-autoalpha` - clicked the real `Lint` button - confirmed the lint modal shows the new warning and the property-preserving `{ autoAlpha: 0 }` fix hint - saved local proof artifacts under `qa-artifacts/issue-473/` ## Notes - the `tmp/issue-473-*` fixtures and `qa-artifacts/issue-473` browser proof are local-only and are not part of this PR - this intentionally stays heuristic-based: it warns near clip start boundaries instead of trying to build a full GSAP execution model - expression-valued GSAP props and deeper regex-parser limitations remain outside this PR's scope; those are parser-hardening work, not required for the bug in #473