@hyperframes/studio 0.6.112 → 0.6.113

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html CHANGED
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>HyperFrames Studio</title>
8
- <script type="module" crossorigin src="/assets/index-C9b6Siu5.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-B8Qzwcpc.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-DP8pPIk2.css">
10
10
  </head>
11
11
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/studio",
3
- "version": "0.6.112",
3
+ "version": "0.6.113",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,9 +36,9 @@
36
36
  "dompurify": "^3.2.4",
37
37
  "marked": "^14.1.4",
38
38
  "mediabunny": "^1.45.3",
39
- "@hyperframes/sdk": "0.6.112",
40
- "@hyperframes/player": "0.6.112",
41
- "@hyperframes/core": "0.6.112"
39
+ "@hyperframes/sdk": "0.6.113",
40
+ "@hyperframes/player": "0.6.113",
41
+ "@hyperframes/core": "0.6.113"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/react": "19",
@@ -52,7 +52,7 @@
52
52
  "vite": "^6.4.2",
53
53
  "vitest": "^3.2.4",
54
54
  "zustand": "^5.0.0",
55
- "@hyperframes/producer": "0.6.112"
55
+ "@hyperframes/producer": "0.6.113"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "react": "19",
@@ -5,6 +5,8 @@ import { roundTo3 } from "../utils/rounding";
5
5
  import {
6
6
  sdkGsapTweenPersist,
7
7
  sdkGsapDeleteAllForSelectorPersist,
8
+ sdkAddWithKeyframesPersist,
9
+ sdkReplaceWithKeyframesPersist,
8
10
  type CutoverDeps,
9
11
  } from "../utils/sdkCutover";
10
12
  import {
@@ -181,10 +183,104 @@ export function useGsapAnimationOps({
181
183
  [activeCompPath, commitMutation, projectIdRef, showToast, sdkSession, sdkDeps],
182
184
  );
183
185
 
186
+ type KeyframeEntry = {
187
+ percentage: number;
188
+ properties: Record<string, number | string>;
189
+ ease?: string;
190
+ auto?: boolean;
191
+ };
192
+
193
+ const addWithKeyframes = useCallback(
194
+ async (
195
+ selection: DomEditSelection,
196
+ targetSelector: string,
197
+ position: number,
198
+ duration: number,
199
+ keyframes: KeyframeEntry[],
200
+ ease?: string,
201
+ label = "Add animation with keyframes",
202
+ ) => {
203
+ if (sdkSession && sdkDeps) {
204
+ const targetPath = selection.sourceFile || activeCompPath || "index.html";
205
+ const handled = await sdkAddWithKeyframesPersist(
206
+ targetPath,
207
+ targetSelector,
208
+ position,
209
+ duration,
210
+ keyframes,
211
+ ease,
212
+ sdkSession,
213
+ sdkDeps,
214
+ { label },
215
+ );
216
+ if (handled) return;
217
+ }
218
+ void commitMutation(
219
+ selection,
220
+ {
221
+ type: "add-with-keyframes",
222
+ targetSelector,
223
+ position,
224
+ duration,
225
+ keyframes,
226
+ ...(ease ? { ease } : {}),
227
+ },
228
+ { label, softReload: true },
229
+ );
230
+ },
231
+ [commitMutation, activeCompPath, sdkSession, sdkDeps],
232
+ );
233
+
234
+ const replaceWithKeyframes = useCallback(
235
+ async (
236
+ selection: DomEditSelection,
237
+ animationId: string,
238
+ targetSelector: string,
239
+ position: number,
240
+ duration: number,
241
+ keyframes: KeyframeEntry[],
242
+ ease?: string,
243
+ label = "Replace animation with keyframes",
244
+ ) => {
245
+ if (sdkSession && sdkDeps) {
246
+ const targetPath = selection.sourceFile || activeCompPath || "index.html";
247
+ const handled = await sdkReplaceWithKeyframesPersist(
248
+ targetPath,
249
+ animationId,
250
+ targetSelector,
251
+ position,
252
+ duration,
253
+ keyframes,
254
+ ease,
255
+ sdkSession,
256
+ sdkDeps,
257
+ { label },
258
+ );
259
+ if (handled) return;
260
+ }
261
+ void commitMutation(
262
+ selection,
263
+ {
264
+ type: "replace-with-keyframes",
265
+ animationId,
266
+ targetSelector,
267
+ position,
268
+ duration,
269
+ keyframes,
270
+ ...(ease ? { ease } : {}),
271
+ },
272
+ { label, softReload: true },
273
+ );
274
+ },
275
+ [commitMutation, activeCompPath, sdkSession, sdkDeps],
276
+ );
277
+
184
278
  return {
185
279
  updateGsapMeta,
186
280
  deleteGsapAnimation,
187
281
  deleteAllForSelector,
188
282
  addGsapAnimation,
283
+ addWithKeyframes,
284
+ replaceWithKeyframes,
189
285
  };
190
286
  }
@@ -435,6 +435,86 @@ export function sdkGsapConvertToKeyframesPersist(
435
435
  );
436
436
  }
437
437
 
438
+ type KeyframeSpec = {
439
+ percentage: number;
440
+ properties: Record<string, number | string>;
441
+ ease?: string;
442
+ auto?: boolean;
443
+ };
444
+
445
+ type KeyframesPayload = {
446
+ targetSelector: string;
447
+ position: number;
448
+ duration: number;
449
+ keyframes: KeyframeSpec[];
450
+ ease?: string;
451
+ };
452
+
453
+ /** Shared inner dispatch for addWithKeyframes / replaceWithKeyframes ops. */
454
+ function dispatchWithKeyframes(
455
+ s: Composition,
456
+ payload: KeyframesPayload,
457
+ animationId?: string,
458
+ ): void {
459
+ if (animationId !== undefined) {
460
+ s.dispatch({ type: "replaceWithKeyframes", animationId, ...payload });
461
+ } else {
462
+ s.dispatch({ type: "addWithKeyframes", ...payload });
463
+ }
464
+ }
465
+
466
+ export function sdkAddWithKeyframesPersist(
467
+ targetPath: string,
468
+ targetSelector: string,
469
+ position: number,
470
+ duration: number,
471
+ keyframes: KeyframeSpec[],
472
+ ease: string | undefined,
473
+ sdkSession: Composition | null | undefined,
474
+ deps: CutoverDeps,
475
+ options?: CutoverOptions,
476
+ ): Promise<boolean> {
477
+ const payload: KeyframesPayload = {
478
+ targetSelector,
479
+ position,
480
+ duration,
481
+ keyframes,
482
+ ...(ease ? { ease } : {}),
483
+ };
484
+ return dispatchGsapOpAndPersist(targetPath, sdkSession, deps, options, (s) =>
485
+ dispatchWithKeyframes(s, payload),
486
+ );
487
+ }
488
+
489
+ export function sdkReplaceWithKeyframesPersist(
490
+ targetPath: string,
491
+ animationId: string,
492
+ targetSelector: string,
493
+ position: number,
494
+ duration: number,
495
+ keyframes: KeyframeSpec[],
496
+ ease: string | undefined,
497
+ sdkSession: Composition | null | undefined,
498
+ deps: CutoverDeps,
499
+ options?: CutoverOptions,
500
+ ): Promise<boolean> {
501
+ const payload: KeyframesPayload = {
502
+ targetSelector,
503
+ position,
504
+ duration,
505
+ keyframes,
506
+ ...(ease ? { ease } : {}),
507
+ };
508
+ return dispatchGsapOpAndPersist(
509
+ targetPath,
510
+ sdkSession,
511
+ deps,
512
+ options,
513
+ (s) => dispatchWithKeyframes(s, payload, animationId),
514
+ { animationId, opLabel: "replaceWithKeyframes" },
515
+ );
516
+ }
517
+
438
518
  export async function sdkDeletePersist(
439
519
  hfId: string,
440
520
  originalContent: string,