Skip to content

fix(core): split-into-property-groups and replace-with-keyframes mutations#1355

Merged
miguel-heygen merged 2 commits into
mainfrom
fix/kf-server-mutations
Jun 12, 2026
Merged

fix(core): split-into-property-groups and replace-with-keyframes mutations#1355
miguel-heygen merged 2 commits into
mainfrom
fix/kf-server-mutations

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add split-into-property-groups server mutation for atomic property-group splitting
  • Add replace-with-keyframes server mutation for keyframe replacement
  • Client commitMutation returns early on changed:false instead of throwing

Test plan

  • Build passes
  • Typecheck clean
  • Mutation endpoints return correct responses

Stack: 2/7 — depends on #1354

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.
…mutations

Server-side mutations for atomic property-group splitting and keyframe
replacement. Client commitMutation returns early on changed:false instead
of throwing.

@james-russo-rames-d-jusso james-russo-rames-d-jusso left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: LGTM with one validation nit. Wire shape correct; new mutations land cleanly.

R2 carry-overs

  • RC5 throw flip ✅ — files.ts:1106changed boolean drives both write-skip and response payload; client (useGsapScriptCommits.ts:135-147) returns early on result.changed === false without throwing. Matches the R2 ask.
  • splitIntoPropertyGroups mutation ✅ — gsapParser.ts:2352-2480 emits per-group tweens; downstream IDs flow through addAnimationWithKeyframesToScript/addAnimationToScript, then re-suffixed via ${baseId}-${propertyGroup} at gsapParser.ts:1047. ID-suffix wire is coherent.
  • replace-with-keyframes purpose — gesture/drag-commit primitive. Consumers at gsapDragCommit.ts:132 and gsapRuntimeBridge.ts:394 (land in #1357) call it to atomically replace a flat tween with a keyframed version.

Concern (validation)

  • files.ts:639-648replace-with-keyframes doesn't validate body.keyframes is a non-empty array. addAnimationWithKeyframesToScript with an empty list silently no-ops the add, but removeAnimationFromScript still runs → data loss on a malformed client call. Wrap in the same shape check as split-animations (line 645).

Test coverage

5 cases for splitIntoPropertyGroups in gsapParser.test.ts:2163-2245 (flat-3-group, flat-2-group, no-op single-group, position/duration/ease preservation, keyframed split). Good coverage. No test for the new replace-with-keyframes route or for changed: false short-circuit in commitMutation.

Cross-PR coherence

Emits propertyGroup on every split-output animation via the re-parse path (anim.propertyGroup line 941). #1357 caches it, #1358 reads it.

Review by Rames D Jusso

@james-russo-rames-d-jusso james-russo-rames-d-jusso left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R3 verification — concerns. Both R2 nits still open.

  • files.ts:649-660case "replace-with-keyframes" still calls addAnimationWithKeyframesToScript(script, ..., body.keyframes, body.ease) with no body.keyframes.length > 0 guard. A request with an empty array silently removes the animation and adds nothing back. Guard at top of case.
  • useGsapScriptCommits.ts:116 — R3 introduced throw new Error(\Mutation failed: ${mutation.type}`)on!result. No toast, no .catch()at the call site. Combined withvoid commitMutation(...)elsewhere this propagates as an unhandled rejection. Either wrap inshowToast(style consistent with #1359'sshowToast("Selection lost during recording", "error")) or attach .catch(showErrorToast)` at call sites.

Review by Rames D Jusso

@vanceingalls vanceingalls left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verification pass — R3 items checked against current HEAD (ec57455).

1. Empty-keyframes guard — case

NOT fixed. HEAD still has no guard:

case "replace-with-keyframes": {
  const script = removeAnimationFromScript(block.scriptText, body.animationId);
  const added = addAnimationWithKeyframesToScript(script, body.targetSelector, body.position, body.duration, body.keyframes, body.ease);
  return added.script;
}

No body.keyframes.length > 0 check. Empty array → silent remove with no replacement, same as R3.

2. Unhandled throw —

NOT fixed. throw new Error(Mutation failed: ...) is still present at line 138, and there are 10+ void commitMutation(...) call sites (lines 205, 242, 255, 337, 347, 362, 376, 386, 486, 508, 527, 537) with no .catch(). These throw as unhandled rejections.

Both R3 blockers remain open. Not stamp-ready.

— Vai (verification pass)

Base automatically changed from fix/kf-parser-foundations to main June 12, 2026 04:02
@miguel-heygen miguel-heygen merged commit b6bf1b1 into main Jun 12, 2026
43 checks passed
@miguel-heygen miguel-heygen deleted the fix/kf-server-mutations branch June 12, 2026 04:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants