Skip to content

Commit 7b669b9

Browse files
feat(studio): route GSAP tween add/update/delete through SDK (§3.5 PR1)
Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com>
1 parent a545e52 commit 7b669b9

7 files changed

Lines changed: 461 additions & 38 deletions

File tree

packages/studio/src/hooks/gsapScriptCommitTypes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { ParsedGsap } from "@hyperframes/core/gsap-parser";
2+
import type { Composition } from "@hyperframes/sdk";
23
import type { DomEditSelection } from "../components/editor/domEditingTypes";
34
import type { EditHistoryKind } from "../utils/editHistory";
45

@@ -55,4 +56,7 @@ export interface GsapScriptCommitsParams {
5556
onCacheInvalidate: () => void;
5657
onFileContentChanged?: (path: string, content: string) => void;
5758
showToast: (message: string, tone?: "error" | "info") => void;
59+
/** Stage 7 §3.5: SDK session for routing GSAP tween ops through addGsapTween/setGsapTween/removeGsapTween. */
60+
sdkSession?: Composition | null;
61+
writeProjectFile?: (path: string, content: string) => Promise<void>;
5862
}

packages/studio/src/hooks/useDomEditSession.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ export function useDomEditSession({
193193
onCacheInvalidate: bumpGsapCache,
194194
onFileContentChanged: updateEditingFileContent,
195195
showToast,
196+
sdkSession,
197+
writeProjectFile,
196198
});
197199

198200
// ── DOM commit handlers ──

packages/studio/src/hooks/useGsapAnimationOps.ts

Lines changed: 122 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
11
import { useCallback } from "react";
2+
import type { Composition } from "@hyperframes/sdk";
23
import type { DomEditSelection } from "../components/editor/domEditingTypes";
34
import { roundTo3 } from "../utils/rounding";
5+
import { sdkGsapTweenPersist } from "../utils/sdkCutover";
46
import {
57
assignGsapTargetAutoIdIfNeeded,
68
ensureElementAddressable,
79
} from "./gsapScriptCommitHelpers";
810
import type { CommitMutation, SafeGsapCommitMutation } from "./gsapScriptCommitTypes";
11+
import type { EditHistoryKind } from "../utils/editHistory";
912

10-
interface GsapAnimationOpsParams {
13+
interface SdkAnimationDeps {
14+
sdkSession?: Composition | null;
15+
writeProjectFile?: (path: string, content: string) => Promise<void>;
16+
editHistory?: {
17+
recordEdit: (entry: {
18+
label: string;
19+
kind: EditHistoryKind;
20+
coalesceKey?: string;
21+
files: Record<string, { before: string; after: string }>;
22+
}) => Promise<void>;
23+
};
24+
reloadPreview?: () => void;
25+
domEditSaveTimestampRef?: React.MutableRefObject<number>;
26+
}
27+
28+
interface GsapAnimationOpsParams extends SdkAnimationDeps {
1129
projectIdRef: React.MutableRefObject<string | null>;
1230
activeCompPath: string | null;
1331
commitMutation: CommitMutation;
@@ -21,38 +39,91 @@ export function useGsapAnimationOps({
2139
commitMutation,
2240
commitMutationSafely,
2341
showToast,
42+
sdkSession,
43+
writeProjectFile,
44+
editHistory,
45+
reloadPreview,
46+
domEditSaveTimestampRef,
2447
}: GsapAnimationOpsParams) {
2548
const updateGsapMeta = useCallback(
26-
(
49+
async (
2750
selection: DomEditSelection,
2851
animationId: string,
2952
updates: { duration?: number; ease?: string; position?: number },
3053
) => {
54+
if (
55+
sdkSession &&
56+
writeProjectFile &&
57+
editHistory &&
58+
reloadPreview &&
59+
domEditSaveTimestampRef
60+
) {
61+
const targetPath = selection.sourceFile || activeCompPath || "index.html";
62+
const handled = await sdkGsapTweenPersist(
63+
targetPath,
64+
{ kind: "set", animationId, properties: updates },
65+
sdkSession,
66+
{ editHistory, writeProjectFile, reloadPreview, domEditSaveTimestampRef },
67+
{ label: "Edit GSAP animation", coalesceKey: `gsap:${animationId}:meta` },
68+
);
69+
if (handled) return;
70+
}
3171
commitMutationSafely(
3272
selection,
3373
{ type: "update-meta", animationId, updates },
34-
{
35-
label: "Edit GSAP animation",
36-
coalesceKey: `gsap:${animationId}:meta`,
37-
},
74+
{ label: "Edit GSAP animation", coalesceKey: `gsap:${animationId}:meta` },
3875
);
3976
},
40-
[commitMutationSafely],
77+
[
78+
commitMutationSafely,
79+
activeCompPath,
80+
sdkSession,
81+
writeProjectFile,
82+
editHistory,
83+
reloadPreview,
84+
domEditSaveTimestampRef,
85+
],
4186
);
4287

4388
const deleteGsapAnimation = useCallback(
44-
(selection: DomEditSelection, animationId: string) => {
89+
async (selection: DomEditSelection, animationId: string) => {
90+
if (
91+
sdkSession &&
92+
writeProjectFile &&
93+
editHistory &&
94+
reloadPreview &&
95+
domEditSaveTimestampRef
96+
) {
97+
const targetPath = selection.sourceFile || activeCompPath || "index.html";
98+
const handled = await sdkGsapTweenPersist(
99+
targetPath,
100+
{ kind: "remove", animationId },
101+
sdkSession,
102+
{ editHistory, writeProjectFile, reloadPreview, domEditSaveTimestampRef },
103+
{ label: "Delete GSAP animation" },
104+
);
105+
if (handled) return;
106+
}
45107
commitMutationSafely(
46108
selection,
47109
{ type: "delete", animationId, stripStudioEdits: true },
48110
{ label: "Delete GSAP animation" },
49111
);
50112
},
51-
[commitMutationSafely],
113+
[
114+
commitMutationSafely,
115+
activeCompPath,
116+
sdkSession,
117+
writeProjectFile,
118+
editHistory,
119+
reloadPreview,
120+
domEditSaveTimestampRef,
121+
],
52122
);
53123

54124
const deleteAllForSelector = useCallback(
55125
(selection: DomEditSelection, targetSelector: string) => {
126+
// ponytail: no SDK op for delete-all-for-selector; stays server-authoritative
56127
void commitMutation(
57128
selection,
58129
{ type: "delete-all-for-selector", targetSelector },
@@ -62,7 +133,9 @@ export function useGsapAnimationOps({
62133
[commitMutation],
63134
);
64135

136+
// fallow-ignore-next-line complexity
65137
const addGsapAnimation = useCallback(
138+
// fallow-ignore-next-line complexity
66139
async (
67140
selection: DomEditSelection,
68141
method: "to" | "from" | "set" | "fromTo",
@@ -95,6 +168,35 @@ export function useGsapAnimationOps({
95168
fromTo: { x: 0, y: 0, opacity: 1 },
96169
};
97170

171+
// SDK path: addGsapTween only supports from/to/fromTo; "set" stays server-side
172+
if (
173+
method !== "set" &&
174+
selection.hfId &&
175+
sdkSession &&
176+
writeProjectFile &&
177+
editHistory &&
178+
reloadPreview &&
179+
domEditSaveTimestampRef
180+
) {
181+
const targetPath = selection.sourceFile || activeCompPath || "index.html";
182+
const spec = {
183+
method: method as "to" | "from" | "fromTo",
184+
position,
185+
duration,
186+
ease: "power2.out" as const,
187+
properties: toDefaults[method] ?? { opacity: 1 },
188+
fromProperties: method === "fromTo" ? { opacity: 0 } : undefined,
189+
};
190+
const handled = await sdkGsapTweenPersist(
191+
targetPath,
192+
{ kind: "add", target: selection.hfId, spec },
193+
sdkSession,
194+
{ editHistory, writeProjectFile, reloadPreview, domEditSaveTimestampRef },
195+
{ label: `Add GSAP ${method} animation` },
196+
);
197+
if (handled) return;
198+
}
199+
98200
await commitMutation(
99201
selection,
100202
{
@@ -110,7 +212,17 @@ export function useGsapAnimationOps({
110212
{ label: `Add GSAP ${method} animation` },
111213
);
112214
},
113-
[activeCompPath, commitMutation, projectIdRef, showToast],
215+
[
216+
activeCompPath,
217+
commitMutation,
218+
projectIdRef,
219+
showToast,
220+
sdkSession,
221+
writeProjectFile,
222+
editHistory,
223+
reloadPreview,
224+
domEditSaveTimestampRef,
225+
],
114226
);
115227

116228
return {

0 commit comments

Comments
 (0)