Skip to content

Commit 4a682ec

Browse files
committed
feat(studio): keyframe cache + commit hooks
Add hooks for keyframe cache population (tween → clip-relative %), mutation dispatch, keyframe snapping, and audio beat detection.
1 parent 00a308f commit 4a682ec

9 files changed

Lines changed: 493 additions & 45 deletions

packages/studio/src/contexts/DomEditContext.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ export function DomEditProvider({
7272
handleGsapRemoveAllKeyframes,
7373
handleResetSelectedElementKeyframes,
7474
commitAnimatedProperty,
75+
handleSetArcPath,
76+
handleUpdateArcSegment,
7577
invalidateGsapCache,
7678
previewIframeRef,
7779
},
@@ -141,6 +143,8 @@ export function DomEditProvider({
141143
handleGsapRemoveAllKeyframes,
142144
handleResetSelectedElementKeyframes,
143145
commitAnimatedProperty,
146+
handleSetArcPath,
147+
handleUpdateArcSegment,
144148
invalidateGsapCache,
145149
previewIframeRef,
146150
}),
@@ -204,6 +208,8 @@ export function DomEditProvider({
204208
handleGsapRemoveAllKeyframes,
205209
handleResetSelectedElementKeyframes,
206210
commitAnimatedProperty,
211+
handleSetArcPath,
212+
handleUpdateArcSegment,
207213
invalidateGsapCache,
208214
previewIframeRef,
209215
],

packages/studio/src/hooks/useDomEditSession.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export interface UseDomEditSessionParams {
5959
queueDomEditSave: (save: () => Promise<void>) => Promise<void>;
6060
readProjectFile: (path: string) => Promise<string>;
6161
writeProjectFile: (path: string, content: string) => Promise<void>;
62+
updateEditingFileContent?: (path: string, content: string) => void;
6263
domEditSaveTimestampRef: React.MutableRefObject<number>;
6364
editHistory: { recordEdit: (entry: RecordEditInput) => Promise<void> };
6465
fileTree: string[];
@@ -100,6 +101,7 @@ export function useDomEditSession({
100101
queueDomEditSave,
101102
readProjectFile: _readProjectFile,
102103
writeProjectFile,
104+
updateEditingFileContent,
103105
domEditSaveTimestampRef,
104106
editHistory,
105107
fileTree,
@@ -224,12 +226,25 @@ export function useDomEditSession({
224226

225227
const { version: gsapCacheVersion, bump: bumpGsapCache } = useGsapCacheVersion();
226228

229+
// Bump GSAP cache when refreshKey changes (code-tab edits trigger iframe
230+
// reload via refreshKey but don't go through commitMutation, so the cache
231+
// would otherwise retain stale keyframe entries).
232+
const prevRefreshKeyRef = useRef(refreshKey);
233+
// eslint-disable-next-line no-restricted-syntax
234+
useEffect(() => {
235+
if (refreshKey !== prevRefreshKeyRef.current) {
236+
prevRefreshKeyRef.current = refreshKey;
237+
bumpGsapCache();
238+
}
239+
}, [refreshKey, bumpGsapCache]);
240+
227241
const gsapSourceFile = domEditSelection?.sourceFile || activeCompPath || "index.html";
228242

229243
usePopulateKeyframeCacheForFile(
230244
STUDIO_GSAP_PANEL_ENABLED ? (projectId ?? null) : null,
231245
gsapSourceFile,
232246
gsapCacheVersion,
247+
previewIframeRef,
233248
);
234249

235250
const {
@@ -260,6 +275,8 @@ export function useDomEditSession({
260275
removeKeyframe,
261276
convertToKeyframes,
262277
removeAllKeyframes,
278+
setArcPath,
279+
updateArcSegment,
263280
} = useGsapScriptCommits({
264281
projectIdRef,
265282
activeCompPath,
@@ -268,6 +285,7 @@ export function useDomEditSession({
268285
domEditSaveTimestampRef,
269286
reloadPreview,
270287
onCacheInvalidate: bumpGsapCache,
288+
onFileContentChanged: updateEditingFileContent,
271289
});
272290

273291
// ── Commit handlers (delegated to useDomEditCommits) ──
@@ -449,6 +467,22 @@ export function useDomEditSession({
449467
bumpGsapCache,
450468
});
451469

470+
const handleSetArcPath = useCallback(
471+
(animId: string, config: Parameters<typeof setArcPath>[2]) => {
472+
if (!domEditSelection) return;
473+
setArcPath(domEditSelection, animId, config);
474+
},
475+
[domEditSelection, setArcPath],
476+
);
477+
478+
const handleUpdateArcSegment = useCallback(
479+
(animId: string, segmentIndex: number, update: Parameters<typeof updateArcSegment>[3]) => {
480+
if (!domEditSelection) return;
481+
updateArcSegment(domEditSelection, animId, segmentIndex, update);
482+
},
483+
[domEditSelection, updateArcSegment],
484+
);
485+
452486
// Sync selection from preview document on load / refresh
453487
// eslint-disable-next-line no-restricted-syntax
454488
useEffect(() => {
@@ -594,6 +628,8 @@ export function useDomEditSession({
594628
handleGsapRemoveAllKeyframes,
595629
handleResetSelectedElementKeyframes,
596630
commitAnimatedProperty,
631+
handleSetArcPath,
632+
handleUpdateArcSegment,
597633
invalidateGsapCache: bumpGsapCache,
598634
previewIframeRef,
599635
};

0 commit comments

Comments
 (0)