mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 06:30:03 +00:00
feat(studio): add a global toggle to stop manual edits from auto-recording keyframes
Adds a control-bar toggle (next to the Add Keyframe diamond) that, when off, makes a manual drag/resize/rotate/panel edit on an already-keyframed element shift the whole tween by the edit's delta instead of inserting or updating a keyframe at the playhead. The animation's shape is preserved, just moved. Wired into every path that can auto-record a keyframe: - canvas drag-to-move (tryGsapDragIntercept, reuses the existing Alt-drag "shift whole path" behavior) - canvas resize/rotate (tryGsapResizeIntercept, tryGsapRotationIntercept) - design-panel property edits (useAnimatedPropertyCommit) - motion-path keyframe-node dragging (MotionPathOverlay), the path a plain click-drag on a keyframed element's canvas shape actually takes, since the element renders exactly at its current keyframe's position The shared shift helper reuses synthesizeFlatTweenKeyframes for materializing a flat tween instead of hand-rolling it, and lives in its own file (gsapWholePropertyOffsetCommit.ts) to keep gsapDragCommit.ts under the 600-line cap, mirroring the existing gsapDragPositionCommit.ts split. Fixes #1808
This commit is contained in:
@@ -26,6 +26,7 @@ import {
|
||||
findSizeSetAnimation,
|
||||
materializeIfDynamic,
|
||||
} from "./gsapDragCommit";
|
||||
import { commitWholePropertyOffset } from "./gsapWholePropertyOffsetCommit";
|
||||
import { resolveTweenStart, resolveTweenDuration } from "../utils/globalTimeCompiler";
|
||||
import type { GsapDragCommitCallbacks } from "./gsapDragCommit";
|
||||
import { selectorFromSelection } from "./gsapShared";
|
||||
@@ -225,7 +226,12 @@ export async function tryGsapDragIntercept(
|
||||
}
|
||||
|
||||
const cbs = { commitMutation, fetchAnimations: fetchFallbackAnimations };
|
||||
if (options?.altKey) {
|
||||
// Alt-drag already means "shift the whole path" — the global auto-keyframe
|
||||
// toggle (#1808) just makes that the default while it's off, so a manual
|
||||
// edit on an already-animated element nudges the animation instead of
|
||||
// inserting/updating a keyframe at the playhead.
|
||||
const autoKeyframeEnabled = usePlayerStore.getState().autoKeyframeEnabled;
|
||||
if (options?.altKey || !autoKeyframeEnabled) {
|
||||
await commitWholePathOffset(selection, posAnim, offset, gsapPos, iframe, selector, cbs);
|
||||
} else {
|
||||
await commitGsapPositionFromDrag(selection, posAnim, offset, gsapPos, iframe, selector, cbs);
|
||||
@@ -332,6 +338,24 @@ export async function tryGsapResizeIntercept(
|
||||
height: Math.round(size.height),
|
||||
};
|
||||
}
|
||||
|
||||
// With auto-keyframe off (#1808), `anim` is already a real (non-"set")
|
||||
// tween for this resize group, so nudge it as a whole rather than adding a
|
||||
// keyframe at the playhead.
|
||||
if (!usePlayerStore.getState().autoKeyframeEnabled) {
|
||||
if (activeKeyframePct != null) setActiveKeyframePct(null);
|
||||
await commitWholePropertyOffset(
|
||||
selection,
|
||||
anim,
|
||||
resizeProps,
|
||||
pct,
|
||||
iframe,
|
||||
{ commitMutation, fetchAnimations: fetchFallbackAnimations },
|
||||
"Resize animation",
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
const ct = usePlayerStore.getState().currentTime;
|
||||
const ts = resolveTweenStart(anim);
|
||||
const td = resolveTweenDuration(anim);
|
||||
@@ -490,6 +514,22 @@ export async function tryGsapRotationIntercept(
|
||||
|
||||
const pct = computeCurrentPercentage(selection, anim);
|
||||
|
||||
// With auto-keyframe off (#1808), a rotation tween already exists for this
|
||||
// element (checked above) so nudge it as a whole rather than adding a
|
||||
// keyframe at the playhead.
|
||||
if (!usePlayerStore.getState().autoKeyframeEnabled) {
|
||||
await commitWholePropertyOffset(
|
||||
selection,
|
||||
anim,
|
||||
{ rotation: newRotation },
|
||||
pct,
|
||||
iframe,
|
||||
{ commitMutation, fetchAnimations: fetchFallbackAnimations },
|
||||
"Rotate animation",
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (anim.hasUnresolvedKeyframes || anim.hasUnresolvedSelector) {
|
||||
const newId = await materializeIfDynamic(anim, iframe, commitMutation, selection);
|
||||
if (newId) anim = { ...anim, id: newId };
|
||||
|
||||
Reference in New Issue
Block a user