Repository navigation
perf(parsers): speed up deleting animated groups - #7463
Merged
Merged
Conversation
miguel-heygen
approved these changes
Nov 9, 2026
miguel-heygen
left a comment
Collaborator
There was a problem hiding this comment.
Reviewed at 0192fbf. The deletion cascade now runs one batched removal per script instead of a parse-and-remove loop for each tween.
Strengths
gsapWriterAcorn.tsremoveAnimationsForSelectors: the batch is equivalent to the old loop, becauseremoveAnimationFromScriptwas onlyremoveCallFromMagicStringon a single located call. I walked the shapes the old loop handled one at a time, and each gives the same result:- a standalone
tl.to/gsap.setstatement is removed whole; - a fully selected chain (
tl.to(a).to(a)) is removed whole throughfullyRemovedStatement, since the root walk reaches thetlidentifier; - a mixed chain splices only the selected links, and a surviving
addLabelor unselected link is kept (pinned by the newit.each); - a chain rooted in
gsap.timeline()still splices, because its root is an unselectedCallExpression; - a selected call inside another selected call's callback gives two nested
MagicStringranges, which is the same result as removing the outer call first.
- a standalone
- The fallback is narrow and correct. The batch can't be trusted only when a removed call encloses the parser's chosen timeline declaration, because
refand the located set change after that. The code then removes one call and reparses, exactly as before. The declarator form and both assignment forms are pinned. htmlParser.test.ts: spying onParser.parsepins one parse per deletion, so a regression back to a per-tween loop fails the test.
Nits (none blocking)
removeAnimationsForSelectorsreturnscurrentwhenremoveAnimationFromScript(first.id)makes no change, so any other selected calls stay in the script. The old loop broke out in the same case, so this isn't a regression. A one-line comment would save the next reader from wondering.
CI: 65 checks passed, 17 skipped, none failed at 0192fbf, including Test, the Windows test shards and lint.
Verdict: APPROVE
Reasoning: the batched removal matches the per-tween loop on every removal shape it handles, the one case where the parse goes stale falls back to the old path, and a test pins the single parse.
SanHsien
added a commit
to SanHsien/hyperframes
that referenced
this pull request
Nov 9, 2026
…heygen-com#7456 and the heygen-com#7439 docs heygen-com#7459: Studio renders take the same one-render-slot lock as the CLI and say they are waiting; Cancel ends the wait. heygen-com#7463: deleting an animated group parses its script once instead of once per tween. heygen-com#7454: seam-gate awaits the async player seek (both skill mirrors). heygen-com#7456: the engine browser test project gets 30 s per test. heygen-com#7439: current ChatGPT and Claude setup steps in the MCP guide. Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
SanHsien
added a commit
to SanHsien/hyperframes
that referenced
this pull request
Nov 9, 2026
…ve more; advance watermark Twelve commits, PRs 7453-7468, issues 7457-7465 and eleven pin moves are recorded with their evidence in the continued ledger, DECISIONS and UPSTREAM. Adopted: heygen-com#7338, heygen-com#7459, heygen-com#7463, heygen-com#7454, heygen-com#7456 and the heygen-com#7439 docs; heygen-com#6732 was already ported. Deferred: heygen-com#7455, heygen-com#7437. Not applicable: heygen-com#7453, heygen-com#7269, heygen-com#7464. The watermark moves to 9e346f9, PR heygen-com#7468, issue heygen-com#7465; four new PRs are pinned and the eleven moved pins re-pinned at their current heads. FORK.md records the fork-only differences in the heygen-com#7338 port; the roadmap tracks the standalone scripts that keep a bare mkdtemp and issue heygen-com#7458. Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Deleting a group with many animated children can tie up Studio's server for seconds. Batch the GSAP cleanup so a normal deletion parses each script once.
Why
The server helper parses a script twice per removed tween, then once more to discover that nothing remains. A 100-tween group takes 201 parses. The new normal path takes one and produces the same serialized HTML.
Five alternating measured rounds after two warmups, Linux arm64 Neoverse-N1, Node v26.13.0. Values are median [minimum, maximum] in milliseconds. This measures the complete synchronous source-deletion helper, including HTML normalization, deletion, CSS cleanup and serialization, using an esbuild harness with third-party dependencies external. Both versions use the same inputs and dependencies; every output is compared byte for byte. Explicit GC happens outside each timed call.
The shared machine was busy, so elapsed-time spread is wide. The 100- and 200-tween CPU medians fall by about 95% and 97%. This is server work, not a measured browser or HTTP latency result. Variant-specific peak memory was not measured; the change adds per-call selection sets and no persistent cache.
Related work
Fixes #7460
#3655 established descendant cleanup. #4932 batches HTTP/HTML work but retains the per-tween parse loop. #4937 optimizes timing edits. Their implementations and review discussions do not cover this remaining parse cost.
How
Select matching AST calls from the original script and remove their spans together. Delete a fully selected statement as a whole; preserve unselected chain links and the existing shared-selector protection.
If removing a callback erases the parser's chosen timeline declaration, remove one match and rediscover the timeline before batching. Astra HIGH review identified this case; it is covered for declarations and both assignment forms. I corrected the finding and reran its reproduction and differential controls. The correction has not received an independent second review.
Design: no behavior or default change; the single-animation writer keeps its existing contract.
Test plan
fails without the fix:
parses a script once when deleting a subtree with many tweensinpackages/parsers/src/htmlParser.test.ts.Baseline for the measurements was
4b3f70fb1b202a1422a199e8b7440a388d0b5a20; the branch is refreshed to7bf19ab5f9d1690d596334822f251dece3921e1a. The intervening main commit adds Engine nightly tests and changes none of the deletion-path files. No browser, native Windows or macOS validation was performed.Verified signed head:
0192fbf3f89c06d7012cd58fb78dc536c20b1afe. The fetched complete tree matches the tested index.