fix(studio): keyframe commit routing for 3D and cross-group edits (#1762)

- pickBestAnimation is group-aware: a rotation/3D edit no longer merges into a
  position tween — a fresh same-group tween with a 0% baseline is created instead
- editing at a playhead past the tween extends it and keyframes there (matches drag)
- update-keyframe MERGES into the existing keyframe instead of overwriting, so
  editing one property no longer drops z/transformPerspective (the lens then
  animated from 0 and the element popped)
- dragging a keyframed element with a constant position tween keyframes rather
  than writing a static set
This commit is contained in:
Miguel Ángel
2026-06-27 11:32:43 -04:00
committed by GitHub
parent 6a729b7e03
commit 2d3b19d255
13 changed files with 467 additions and 125 deletions
@@ -241,8 +241,15 @@ export async function tryGsapDragIntercept(
// place (idempotent), else add a new one. This also covers the stale-cache
// phantom — committing a set is correct because the element genuinely has no live motion.
const hasNonHold = hasNonHoldTweenForElement(iframe, selector);
if (!hasNonHold) {
// A KEYFRAMED position tween — even one that's currently a flat constant ("hold",
// e.g. 0% and 100% identical) — is still an animation the user is building, so a
// drag must add/update a keyframe, NOT fall back to a static `set`. Without this,
// dragging an element whose position tween is constant writes a `gsap.set` that
// fights the tween (the "drag didn't create a keyframe / didn't persist" bug). The
// static path is only for elements with NO keyframed position tween (truly static,
// or just a leftover position-hold `set`).
const hasKeyframedPosTween = !!posAnim?.keyframes;
if (!hasNonHold && !hasKeyframedPosTween) {
const existingSet =
posAnim && posAnim.method === "set" && posAnim.targetSelector === selector
? posAnim