mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-13 07:40:06 +00:00
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:
@@ -2348,6 +2348,23 @@ export function updateKeyframeInScript(
|
||||
// `properties` would wipe the primitive — leave the keyframe untouched.
|
||||
return script;
|
||||
}
|
||||
// MERGE edited props into the existing keyframe, preserving props not in this edit
|
||||
// (z, transformPerspective, rotation, …). A whole-value rebuild drops them, so editing
|
||||
// one prop at the 0% keyframe strips z/transformPerspective and the element pops.
|
||||
// Mirrors acorn updateKeyframeInScript; parity-locked by gsapWriterParity.corpus.
|
||||
const existing = match.prop.value;
|
||||
if (existing?.type === "ObjectExpression") {
|
||||
const props = (existing.properties ?? []) as AstNode[];
|
||||
const upsert = (key: string, valueCode: string) => {
|
||||
const idx = props.findIndex((p: AstNode) => isObjectProperty(p) && propKeyName(p) === key);
|
||||
const node = parseExpr(`({ ${safeKey(key)}: ${valueCode} })`).properties[0];
|
||||
if (idx >= 0) props[idx] = node;
|
||||
else props.push(node);
|
||||
};
|
||||
for (const [k, v] of Object.entries(properties)) upsert(k, valueToCode(v));
|
||||
if (ease !== undefined) upsert("ease", JSON.stringify(ease));
|
||||
return recast.print(loc.parsed.ast).code;
|
||||
}
|
||||
match.prop.value = buildKeyframeValueNode(properties, ease);
|
||||
return recast.print(loc.parsed.ast).code;
|
||||
}
|
||||
|
||||
@@ -780,10 +780,22 @@ export function updateKeyframeInScript(
|
||||
const match = findKfPropByPct(kfPropNode.value, percentage);
|
||||
if (!match) return script;
|
||||
|
||||
const record: Record<string, number | string> = { ...properties };
|
||||
if (ease) record.ease = ease;
|
||||
const ms = new MagicString(script);
|
||||
ms.overwrite(match.prop.value.start, match.prop.value.end, recordToCode(record));
|
||||
// MERGE the edited props into the existing keyframe, preserving properties already
|
||||
// keyframed at this percentage (z, transformPerspective, rotation, …). A whole-value
|
||||
// overwrite DROPS every prop not in this edit — e.g. editing rotationY at the 0%
|
||||
// keyframe would strip z / transformPerspective, so the lens then animates from 0 and
|
||||
// the element pops. Mirrors addKeyframeToScript's merge-into-existing branch.
|
||||
if (match.prop.value?.type === "ObjectExpression") {
|
||||
for (const [k, v] of Object.entries(properties)) {
|
||||
upsertProp(ms, match.prop.value, k, v);
|
||||
}
|
||||
if (ease !== undefined) upsertProp(ms, match.prop.value, "ease", ease);
|
||||
} else {
|
||||
const record: Record<string, number | string> = { ...properties };
|
||||
if (ease) record.ease = ease;
|
||||
ms.overwrite(match.prop.value.start, match.prop.value.end, recordToCode(record));
|
||||
}
|
||||
return ms.toString();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user