mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
fix(studio): fix array-form keyframe writes, diamond click-deselect, and nested video sync
- fs.watch's async 'error' event had no listener, crashing the preview
server on EMFILE (exhausted OS watch handles)
- moveKeyframeInScript/resizeKeyframedTweenInScript/removeAllKeyframesFromScript
required object-form keyframes: {"0%": {...}}, silently no-opping on
array-form keyframes: [{...}, {...}]
- a keyframe diamond click's auto-synthesized native click event bubbled
to the ancestor clip's onClick, which toggles selection off when the
clip is already selected (the state every diamond click happens in)
- the clip's trim-resize handles (z-index 4) visually and functionally
covered any keyframe diamond within their 14px edge strip
- synthesizeFlatTweenKeyframes didn't recognize a collapsed
duration:0 + immediateRender static hold (what remove-all-keyframes
produces) as non-animated, so it kept showing a phantom diamond after
Delete All Keyframes
- resolveMediaStartSeconds's fast path for elements with their own
data-start discarded the host composition's inherited start offset,
so a video nested inside a sub-composition played from the root
timeline's time instead of holding until its parent scene began
Fixes #1838
This commit is contained in:
@@ -23,12 +23,18 @@ export function deduplicateKeyframes(
|
||||
|
||||
// fallow-ignore-next-line complexity
|
||||
export function synthesizeFlatTweenKeyframes(anim: GsapAnimation): GsapKeyframesData | null {
|
||||
if (anim.method === "set") {
|
||||
// A `set` is a STATIC HOLD — a value applied at one point, not an animated
|
||||
// keyframe. It must NOT synthesize a keyframe, or the timeline + panel show a
|
||||
// phantom diamond for a value that doesn't animate. This holds for a base
|
||||
// `gsap.set` (off-timeline) AND an on-timeline `tl.set`, and aligns the AST
|
||||
// path with the runtime scan, which already skips every zero-duration set.
|
||||
// Both parsers store extras as raw source text (`__raw:${code}`) so
|
||||
// non-editable config like `stagger: {...}` survives verbatim — a literal
|
||||
// `immediateRender: true` prints as exactly this string, not a boolean.
|
||||
const hasImmediateRenderHold = anim.extras?.immediateRender === "__raw:true";
|
||||
if (anim.method === "set" || (anim.duration === 0 && hasImmediateRenderHold)) {
|
||||
// A `set` — or a `to()`/`from()` collapsed to a zero-duration
|
||||
// immediateRender hold (what removeAllKeyframesFromScript collapses a
|
||||
// keyframed tween to) — is a STATIC HOLD: a value applied at one point,
|
||||
// not an animated keyframe. It must NOT synthesize a keyframe, or the
|
||||
// timeline + panel show a phantom diamond for a value that doesn't
|
||||
// animate. This aligns the AST path with the runtime scan, which already
|
||||
// skips every zero-duration set.
|
||||
return null;
|
||||
}
|
||||
const toProps = anim.properties;
|
||||
|
||||
Reference in New Issue
Block a user