mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 23:00: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:
@@ -3,6 +3,7 @@ import type { DomEditSelection } from "./domEditing";
|
||||
import { useDomEditContext } from "../../contexts/DomEditContext";
|
||||
import { usePlayerStore } from "../../player/store/playerStore";
|
||||
import { parkPlayheadOnKeyframe } from "../../hooks/gsapDragCommit";
|
||||
import { commitWholePropertyOffset } from "../../hooks/gsapWholePropertyOffsetCommit";
|
||||
import { nearestPointOnPath, type MotionNodeRef } from "./motionPathGeometry";
|
||||
import { editableAnimationId, selectorFor } from "./motionPathSelection";
|
||||
import { ACCENT, MotionPathNode } from "./MotionPathNode";
|
||||
@@ -334,13 +335,35 @@ export const MotionPathOverlay = memo(function MotionPathOverlay({
|
||||
// high zoom) would commit an identical value — a no-op undo entry. Skip the
|
||||
// commit, but don't treat it as a click either (the user did drag).
|
||||
if (x === Math.round(d.initX) && y === Math.round(d.initY)) return;
|
||||
void commitNode(d.ref, x, y, animId, commitMutation);
|
||||
// With auto-keyframe off (#1808), dragging a keyframe's node on the motion
|
||||
// path (the common way to nudge a KEYFRAMED element's position on canvas,
|
||||
// since the element renders exactly at its current keyframe) shifts the
|
||||
// whole path instead of moving just that one keyframe.
|
||||
const anim =
|
||||
d.ref.type === "keyframe" ? selectedGsapAnimations?.find((a) => a.id === animId) : undefined;
|
||||
if (
|
||||
d.ref.type === "keyframe" &&
|
||||
anim &&
|
||||
selection &&
|
||||
!usePlayerStore.getState().autoKeyframeEnabled
|
||||
) {
|
||||
void commitWholePropertyOffset(
|
||||
selection,
|
||||
anim,
|
||||
{ x, y },
|
||||
d.ref.pct,
|
||||
iframeRef.current,
|
||||
{ commitMutation: (_sel, mutation, options) => commitMutation(mutation, options) },
|
||||
"Move animation path",
|
||||
);
|
||||
} else {
|
||||
void commitNode(d.ref, x, y, animId, commitMutation);
|
||||
}
|
||||
// Park the playhead on the edited keyframe's time so the element previews AT
|
||||
// that keyframe. Without it, a playhead sitting before the tween renders the
|
||||
// element's base pose — the edit (correct on the path) looks like it vanished.
|
||||
if (d.ref.type === "keyframe") {
|
||||
const anim = selectedGsapAnimations?.find((a) => a.id === animId);
|
||||
if (anim) parkPlayheadOnKeyframe(anim, d.ref.pct);
|
||||
if (d.ref.type === "keyframe" && anim) {
|
||||
parkPlayheadOnKeyframe(anim, d.ref.pct);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user