mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-14 18:01:20 +08:00
7f167ea7c5
Deriving timeline elements from a clip manifest called findTimelineDomNodeForClip once per clip, and each of those calls rebuilt the document's whole candidate set: a `[data-start]` query plus a four-selector `closest()` on every node it returned. On a 273-clip project that quadratic pass ran on every manifest message (~1/s) and was the largest task in the app — 99ms of `getTimelineDomNodes` alone across a ten-click window, with single frames stretching past 100ms. The scan is now a TimelineDomPass built once per derivation and dropped with it. It stays pass-scoped on purpose: the preview document mutates between manifests, so a cached scan that outlived one would resolve a clip to a detached node — selecting the wrong element, far worse than a slow scan. Claiming the resolved node moved into the resolver so a shared pass can never hand two clips the same element. Two per-selection costs in the property panel go with it, since every selection re-renders it: detectAvailableWeights ran nine synchronous `document.fonts.check()` calls per click and is now cached per family and cleared on `loadingdone`, and the font dropdown's ~1,500-entry catalogue — keyed on the selected family, so no memo could hold across clicks — is only built while the dropdown is actually open. Measured on a 273-clip / 40-track fixture, production React, headless Chrome, ten clip selections: main-thread script 388ms -> 261ms (-33%) idle, no clicks 648ms -> 297ms (-54%, 4x CPU throttle) longest frame 50ms -> 25ms 4x throttle p95 41.6ms -> 33.3ms, max 133ms -> 92ms