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:
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* commitWholePropertyOffset — extracted from gsapDragCommit.ts to keep file
|
||||
* sizes under the 600-line limit (mirrors gsapDragPositionCommit.ts).
|
||||
*/
|
||||
import type { GsapAnimation } from "@hyperframes/core/gsap-parser";
|
||||
import type { DomEditSelection } from "../components/editor/domEditingTypes";
|
||||
import { resolveTweenStart, resolveTweenDuration } from "../utils/globalTimeCompiler";
|
||||
import { roundTo3 } from "../utils/rounding";
|
||||
import { PROPERTY_DEFAULTS } from "./gsapShared";
|
||||
import { synthesizeFlatTweenKeyframes } from "./gsapTweenSynth";
|
||||
import { materializeIfDynamic, type GsapDragCommitCallbacks } from "./gsapDragCommit";
|
||||
|
||||
/**
|
||||
* Generic sibling of commitWholePathOffset for property groups other than
|
||||
* position (rotation, size, scale) — shift every keyframe of `anim` by the
|
||||
* same delta for each key in `newValues`, preserving the tween's shape. The
|
||||
* delta is computed against the keyframe NEAREST `currentPct` (the one an
|
||||
* ordinary edit would otherwise overwrite), not the live DOM: by the time a
|
||||
* drag gesture reaches its commit step, the preview has often already
|
||||
* gsap.set the dragged property to its new value, so the DOM can no longer
|
||||
* tell "old" from "new".
|
||||
*/
|
||||
export async function commitWholePropertyOffset(
|
||||
selection: DomEditSelection,
|
||||
anim: GsapAnimation,
|
||||
newValues: Record<string, number>,
|
||||
currentPct: number,
|
||||
iframe: HTMLIFrameElement | null,
|
||||
callbacks: GsapDragCommitCallbacks,
|
||||
label: string,
|
||||
): Promise<void> {
|
||||
let effectiveAnim = anim;
|
||||
if (anim.keyframes) {
|
||||
const newId = await materializeIfDynamic(anim, iframe, callbacks.commitMutation, selection);
|
||||
if (newId) effectiveAnim = { ...anim, id: newId };
|
||||
}
|
||||
|
||||
const ts = resolveTweenStart(effectiveAnim);
|
||||
const td = resolveTweenDuration(effectiveAnim);
|
||||
const ease = effectiveAnim.keyframes?.easeEach ?? effectiveAnim.ease;
|
||||
const keys = Object.keys(newValues);
|
||||
const at = (props: Record<string, number | string>, key: string) =>
|
||||
typeof props[key] === "number" ? (props[key] as number) : (PROPERTY_DEFAULTS[key] ?? 0);
|
||||
|
||||
const kfs =
|
||||
effectiveAnim.keyframes?.keyframes ??
|
||||
synthesizeFlatTweenKeyframes(effectiveAnim)?.keyframes ??
|
||||
[];
|
||||
const nearest = kfs.reduce((best, kf) =>
|
||||
Math.abs(kf.percentage - currentPct) < Math.abs(best.percentage - currentPct) ? kf : best,
|
||||
);
|
||||
|
||||
const shifted = kfs.map((kf) => {
|
||||
const properties = { ...kf.properties };
|
||||
for (const key of keys) {
|
||||
properties[key] = roundTo3(
|
||||
at(properties, key) + (newValues[key]! - at(nearest.properties, key)),
|
||||
);
|
||||
}
|
||||
return { percentage: kf.percentage, properties, ...(kf.ease ? { ease: kf.ease } : {}) };
|
||||
});
|
||||
|
||||
await callbacks.commitMutation(
|
||||
selection,
|
||||
{
|
||||
type: "replace-with-keyframes",
|
||||
animationId: effectiveAnim.id,
|
||||
targetSelector: effectiveAnim.targetSelector,
|
||||
position: roundTo3(ts ?? 0),
|
||||
duration: roundTo3(td || 1),
|
||||
keyframes: shifted,
|
||||
ease,
|
||||
},
|
||||
{ label, softReload: true },
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user