mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 07:19:52 +00:00
fix(studio): property panel group-aware keyframe routing (#1358)
* fix(core): per-property-group keyframe foundations
Add PropertyGroupName type system (position/scale/size/rotation/visual/other),
PROPERTY_GROUPS constant, classifyPropertyGroup/classifyTweenPropertyGroup
functions. Parser generates group-aware animation IDs, resolves position strings
(+=, -=, <, >), uses numeric matching with 2% tolerance, and preserves IDs
across all mutations.
* fix(core): add split-into-property-groups and replace-with-keyframes mutations
Server-side mutations for atomic property-group splitting and keyframe
replacement. Client commitMutation returns early on changed:false instead
of throwing.
* fix(studio): per-property-group intercept routing + drag/resize fixes
Rewire GSAP runtime bridge for property-group routing: drag sends only {x,y}
to position group, resize routes to scale group via data-hf-studio-original-width,
rotation routes to rotation group. Add resolveGroupTween helper, from-extend
with split-first-then-position-only pattern, autoKeyframeEnabled guards,
GSAP base + delta fix in drag draft, cancel-restores-GSAP-x/y from data attrs.
* fix(studio): keyframe cache propertyGroup tagging + timeline UI fixes
Tag cached keyframes with propertyGroup for group-aware operations.
Add tweenPercentage for accurate keyframe matching, activeKeyframePct
for diamond-click targeting, context menu offset, selected diamond z-index,
clearProps after kill in soft reload.
* fix(studio): property panel group-aware keyframe routing
Add animIdForProp helper routing keyframe diamonds to correct property-group
animation. Wire StudioPreviewArea delete/move/toggle handlers to use
propertyGroup for routing. Fix per-property epsilon in rdpSimplify.
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
readGsapBorderRadiusForPanel,
|
||||
} from "./propertyPanelHelpers";
|
||||
import { MetricField, Section } from "./propertyPanelPrimitives";
|
||||
import { classifyPropertyGroup } from "@hyperframes/core/gsap-parser";
|
||||
import { isMediaElement, MediaSection } from "./propertyPanelMediaSection";
|
||||
import { TextSection, StyleSections } from "./propertyPanelSections";
|
||||
import { GsapAnimationSection } from "./GsapAnimationSection";
|
||||
@@ -227,6 +228,13 @@ export const PropertyPanel = memo(function PropertyPanel({
|
||||
const navKeyframes = cacheEntry?.keyframes ?? gsapKeyframes;
|
||||
const seekFromKfPct = (pct: number) => onSeekToTime?.(elStart + (pct / 100) * elDuration);
|
||||
|
||||
const animIdForProp = (prop: string): string => {
|
||||
const group = classifyPropertyGroup(prop);
|
||||
const groupAnim = gsapAnimations?.find((a) => a.propertyGroup === group);
|
||||
if (groupAnim) return groupAnim.id;
|
||||
return gsapAnimId ?? "";
|
||||
};
|
||||
|
||||
// Read ALL GSAP-interpolated values at the current seek time.
|
||||
const gsapRuntimeValues = readGsapRuntimeValuesForPanel(
|
||||
gsapAnimId,
|
||||
@@ -395,8 +403,8 @@ export const PropertyPanel = memo(function PropertyPanel({
|
||||
onCommitAnimatedProperty &&
|
||||
void onCommitAnimatedProperty(element, "x", displayX)
|
||||
}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(gsapAnimId, pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(gsapAnimId)}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(animIdForProp("x"), pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(animIdForProp("x"))}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -420,8 +428,8 @@ export const PropertyPanel = memo(function PropertyPanel({
|
||||
onCommitAnimatedProperty &&
|
||||
void onCommitAnimatedProperty(element, "y", displayY)
|
||||
}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(gsapAnimId, pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(gsapAnimId)}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(animIdForProp("y"), pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(animIdForProp("y"))}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -445,8 +453,8 @@ export const PropertyPanel = memo(function PropertyPanel({
|
||||
onCommitAnimatedProperty &&
|
||||
void onCommitAnimatedProperty(element, "width", displayW)
|
||||
}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(gsapAnimId, pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(gsapAnimId)}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(animIdForProp("width"), pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(animIdForProp("width"))}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -470,8 +478,8 @@ export const PropertyPanel = memo(function PropertyPanel({
|
||||
onCommitAnimatedProperty &&
|
||||
void onCommitAnimatedProperty(element, "height", displayH)
|
||||
}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(gsapAnimId, pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(gsapAnimId)}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(animIdForProp("height"), pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(animIdForProp("height"))}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -493,8 +501,8 @@ export const PropertyPanel = memo(function PropertyPanel({
|
||||
onCommitAnimatedProperty &&
|
||||
void onCommitAnimatedProperty(element, "rotation", displayR)
|
||||
}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(gsapAnimId, pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(gsapAnimId)}
|
||||
onRemoveKeyframe={(pct) => onRemoveKeyframe?.(animIdForProp("rotation"), pct)}
|
||||
onConvertToKeyframes={() => onConvertToKeyframes?.(animIdForProp("rotation"))}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -503,6 +511,7 @@ export const PropertyPanel = memo(function PropertyPanel({
|
||||
<PropertyPanel3dTransform
|
||||
gsapRuntimeValues={gsapRuntimeValues}
|
||||
gsapAnimId={gsapAnimId}
|
||||
resolveAnimIdForProp={animIdForProp}
|
||||
gsapKeyframes={navKeyframes}
|
||||
currentPct={currentPct}
|
||||
elStart={elStart}
|
||||
|
||||
Reference in New Issue
Block a user