@hyperframes/studio-server 0.7.63 → 0.7.65

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.
@@ -1,12 +1 @@
1
- /**
2
- * Draft-marker constants shared between core's PreviewAdapter and Studio's
3
- * manual-edits code. CSS custom properties written during a drag gesture, plus
4
- * the gesture marker attribute. Exported from @hyperframes/core/studio-api/draft-markers.
5
- */
6
- declare const STUDIO_OFFSET_X_PROP = "--hf-studio-offset-x";
7
- declare const STUDIO_OFFSET_Y_PROP = "--hf-studio-offset-y";
8
- declare const STUDIO_WIDTH_PROP = "--hf-studio-width";
9
- declare const STUDIO_HEIGHT_PROP = "--hf-studio-height";
10
- declare const STUDIO_MANUAL_EDIT_GESTURE_ATTR = "data-hf-studio-manual-edit-gesture";
11
-
12
- export { STUDIO_HEIGHT_PROP, STUDIO_MANUAL_EDIT_GESTURE_ATTR, STUDIO_OFFSET_X_PROP, STUDIO_OFFSET_Y_PROP, STUDIO_WIDTH_PROP };
1
+ export * from '@hyperframes/core/editing/draft-markers';
@@ -1,14 +1,3 @@
1
1
  // src/helpers/draftMarkers.ts
2
- var STUDIO_OFFSET_X_PROP = "--hf-studio-offset-x";
3
- var STUDIO_OFFSET_Y_PROP = "--hf-studio-offset-y";
4
- var STUDIO_WIDTH_PROP = "--hf-studio-width";
5
- var STUDIO_HEIGHT_PROP = "--hf-studio-height";
6
- var STUDIO_MANUAL_EDIT_GESTURE_ATTR = "data-hf-studio-manual-edit-gesture";
7
- export {
8
- STUDIO_HEIGHT_PROP,
9
- STUDIO_MANUAL_EDIT_GESTURE_ATTR,
10
- STUDIO_OFFSET_X_PROP,
11
- STUDIO_OFFSET_Y_PROP,
12
- STUDIO_WIDTH_PROP
13
- };
2
+ export * from "@hyperframes/core/editing/draft-markers";
14
3
  //# sourceMappingURL=draftMarkers.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/helpers/draftMarkers.ts"],"sourcesContent":["/**\n * Draft-marker constants shared between core's PreviewAdapter and Studio's\n * manual-edits code. CSS custom properties written during a drag gesture, plus\n * the gesture marker attribute. Exported from @hyperframes/core/studio-api/draft-markers.\n */\nexport const STUDIO_OFFSET_X_PROP = \"--hf-studio-offset-x\";\nexport const STUDIO_OFFSET_Y_PROP = \"--hf-studio-offset-y\";\nexport const STUDIO_WIDTH_PROP = \"--hf-studio-width\";\nexport const STUDIO_HEIGHT_PROP = \"--hf-studio-height\";\nexport const STUDIO_MANUAL_EDIT_GESTURE_ATTR = \"data-hf-studio-manual-edit-gesture\";\n"],"mappings":";AAKO,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,IAAM,oBAAoB;AAC1B,IAAM,qBAAqB;AAC3B,IAAM,kCAAkC;","names":[]}
1
+ {"version":3,"sources":["../../src/helpers/draftMarkers.ts"],"sourcesContent":["/**\n * Compatibility export for server consumers. The edit-protocol constants are\n * owned by core's dependency-free browser contract.\n */\nexport * from \"@hyperframes/core/editing/draft-markers\";\n"],"mappings":";AAIA,cAAc;","names":[]}
package/dist/index.js CHANGED
@@ -646,13 +646,18 @@ import {
646
646
  unrollDynamicAnimations,
647
647
  setArcPathInScript,
648
648
  updateArcSegmentInScript,
649
+ updateMotionPathPointInScript,
650
+ addMotionPathPointInScript,
651
+ removeMotionPathPointInScript,
652
+ addMotionPathToScript,
649
653
  removeArcPathFromScript,
650
654
  addAnimationWithKeyframesToScript,
651
655
  splitAnimationsInScript,
652
656
  splitIntoPropertyGroupsFromScript,
653
657
  shiftPositionsInScript,
654
658
  scalePositionsInScript,
655
- dedupePositionWritesInScript
659
+ dedupePositionWritesInScript,
660
+ syncPositionHoldsBeforeKeyframes
656
661
  } from "@hyperframes/parsers/gsap-writer-acorn";
657
662
  import { parseHTML as parseHTML2 } from "linkedom";
658
663
 
@@ -843,11 +848,69 @@ function insertCompositionIntoSource(input) {
843
848
  return { html: document.toString(), hostId, track, duration };
844
849
  }
845
850
 
846
- // src/routes/files.ts
847
- function isAcornGsapWriterEnabled() {
848
- const val = process.env["STUDIO_SDK_CUTOVER_ENABLED"];
849
- return val === "true" || val === "1";
851
+ // src/routes/gsapMutationCapabilities.ts
852
+ var differential = (family) => ({
853
+ family,
854
+ acorn: "supported",
855
+ recast: "supported",
856
+ parity: "differential"
857
+ });
858
+ var behavioral = (family) => ({
859
+ family,
860
+ acorn: "supported",
861
+ recast: "supported",
862
+ parity: "behavioral"
863
+ });
864
+ var GSAP_MUTATION_CAPABILITIES = {
865
+ "update-property": differential("animation"),
866
+ "update-properties": differential("animation"),
867
+ "update-from-property": differential("animation"),
868
+ "update-meta": differential("animation"),
869
+ add: differential("animation"),
870
+ delete: differential("animation"),
871
+ "add-property": differential("animation"),
872
+ "add-from-property": differential("animation"),
873
+ "remove-property": differential("animation"),
874
+ "remove-from-property": differential("animation"),
875
+ "add-keyframe": differential("keyframe"),
876
+ "remove-keyframe": differential("keyframe"),
877
+ "move-keyframe": behavioral("keyframe"),
878
+ "resize-keyframed-tween": behavioral("keyframe"),
879
+ "update-keyframe": differential("keyframe"),
880
+ "convert-to-keyframes": behavioral("keyframe"),
881
+ "remove-all-keyframes": behavioral("keyframe"),
882
+ "materialize-keyframes": behavioral("keyframe"),
883
+ "set-arc-path": behavioral("motion_path"),
884
+ "update-arc-segment": behavioral("motion_path"),
885
+ "update-motion-path-point": differential("motion_path"),
886
+ "add-motion-path-point": differential("motion_path"),
887
+ "remove-motion-path-point": differential("motion_path"),
888
+ "add-motion-path": differential("motion_path"),
889
+ "remove-arc-path": behavioral("motion_path"),
890
+ "add-with-keyframes": behavioral("keyframe"),
891
+ "replace-with-keyframes": behavioral("keyframe"),
892
+ "split-animations": behavioral("structure"),
893
+ "split-into-property-groups": behavioral("structure"),
894
+ "delete-all-for-selector": behavioral("structure"),
895
+ "consolidate-position-writes": behavioral("structure"),
896
+ "unroll-timeline": behavioral("structure"),
897
+ "shift-positions": behavioral("timing"),
898
+ "shift-positions-batch": behavioral("timing"),
899
+ "scale-positions": behavioral("timing")
900
+ };
901
+ var GSAP_WRITER_MIGRATION = Object.freeze({
902
+ flag: "HYPERFRAMES_GSAP_WRITER",
903
+ owner: "studio-foundations",
904
+ deadline: "2026-09-30",
905
+ graduationCriteria: "Every operation has differential parity, the Acorn path imports no Recast runtime, and canary divergence is zero for the agreed soak window."
906
+ });
907
+ function resolveGsapWriter(env) {
908
+ const configured = env.HYPERFRAMES_GSAP_WRITER ?? "recast";
909
+ if (configured === "recast" || configured === "acorn") return configured;
910
+ throw new Error(`Invalid ${GSAP_WRITER_MIGRATION.flag}=${configured}; expected recast or acorn`);
850
911
  }
912
+
913
+ // src/routes/files.ts
851
914
  async function loadGsapParser() {
852
915
  return import("@hyperframes/parsers/gsap-parser-recast");
853
916
  }
@@ -1318,8 +1381,8 @@ var HOLD_SYNC_MUTATION_TYPES = /* @__PURE__ */ new Set([
1318
1381
  "delete",
1319
1382
  "delete-all-for-selector"
1320
1383
  ]);
1321
- async function executeGsapMutation(body, block, respond) {
1322
- if (!isAcornGsapWriterEnabled()) {
1384
+ async function executeGsapMutation(body, block, respond, writer) {
1385
+ if (writer === "recast") {
1323
1386
  return executeGsapMutationRecast(body, block, respond);
1324
1387
  }
1325
1388
  return executeGsapMutationAcorn(body, block, respond);
@@ -1380,16 +1443,23 @@ async function applyGsapMutations(c, res, mutations) {
1380
1443
  const initialScript = block.scriptText;
1381
1444
  const skippedSelectors = /* @__PURE__ */ new Set();
1382
1445
  const respond = (data, status) => status ? c.json(data, status) : c.json(data);
1446
+ let writer;
1447
+ try {
1448
+ writer = resolveGsapWriter({
1449
+ HYPERFRAMES_GSAP_WRITER: process.env["HYPERFRAMES_GSAP_WRITER"]
1450
+ });
1451
+ } catch (error) {
1452
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
1453
+ }
1383
1454
  for (const mutation of mutations) {
1384
- const result = await executeGsapMutation(mutation, block, respond);
1455
+ const result = await executeGsapMutation(mutation, block, respond, writer);
1385
1456
  if (result instanceof Response) return result;
1386
1457
  let newScript = typeof result === "string" ? result : result.script;
1387
1458
  if (typeof result !== "string") {
1388
1459
  for (const selector of result.skippedSelectors) skippedSelectors.add(selector);
1389
1460
  }
1390
1461
  if (HOLD_SYNC_MUTATION_TYPES.has(mutation.type)) {
1391
- const parser = await loadGsapParser();
1392
- newScript = parser.syncPositionHoldsBeforeKeyframes(newScript);
1462
+ newScript = writer === "acorn" ? syncPositionHoldsBeforeKeyframes(newScript) : (await loadGsapParser()).syncPositionHoldsBeforeKeyframes(newScript);
1393
1463
  }
1394
1464
  block.scriptText = newScript;
1395
1465
  }
@@ -1468,6 +1538,12 @@ function executeGsapMutationAcorn(body, block, respond) {
1468
1538
  if (body.fromProperties && body.method !== "fromTo") {
1469
1539
  return respond({ error: "fromProperties is only valid for method=fromTo" }, 400);
1470
1540
  }
1541
+ if (Object.keys(body.properties).some((key) => {
1542
+ const group = classifyPropertyGroup(key);
1543
+ return group === "position" || group === "rotation";
1544
+ })) {
1545
+ stripStudioEditsFromTarget(block.document, body.targetSelector);
1546
+ }
1471
1547
  const result = addAnimationToScript(block.scriptText, {
1472
1548
  targetSelector: body.targetSelector,
1473
1549
  method: body.method,
@@ -1605,10 +1681,38 @@ function executeGsapMutationAcorn(body, block, respond) {
1605
1681
  ...body.cp2 ? { cp2: body.cp2 } : {}
1606
1682
  });
1607
1683
  }
1684
+ case "update-motion-path-point": {
1685
+ return updateMotionPathPointInScript(block.scriptText, body.animationId, body.pointIndex, {
1686
+ x: body.x,
1687
+ y: body.y
1688
+ });
1689
+ }
1690
+ case "add-motion-path-point": {
1691
+ return addMotionPathPointInScript(block.scriptText, body.animationId, body.index, {
1692
+ x: body.x,
1693
+ y: body.y
1694
+ });
1695
+ }
1696
+ case "remove-motion-path-point": {
1697
+ return removeMotionPathPointInScript(block.scriptText, body.animationId, body.index);
1698
+ }
1699
+ case "add-motion-path": {
1700
+ return addMotionPathToScript(
1701
+ block.scriptText,
1702
+ body.targetSelector,
1703
+ body.position,
1704
+ body.duration,
1705
+ { x: body.x, y: body.y },
1706
+ body.ease
1707
+ ).script;
1708
+ }
1608
1709
  case "remove-arc-path": {
1609
1710
  return removeArcPathFromScript(block.scriptText, body.animationId);
1610
1711
  }
1611
1712
  case "add-with-keyframes": {
1713
+ if (keyframesWritePosition(body.keyframes) || keyframesWriteRotation(body.keyframes)) {
1714
+ stripStudioEditsFromTarget(block.document, body.targetSelector);
1715
+ }
1612
1716
  const result = addAnimationWithKeyframesToScript(
1613
1717
  block.scriptText,
1614
1718
  body.targetSelector,
@@ -1621,6 +1725,9 @@ function executeGsapMutationAcorn(body, block, respond) {
1621
1725
  return result.script;
1622
1726
  }
1623
1727
  case "replace-with-keyframes": {
1728
+ if (keyframesWritePosition(body.keyframes) || keyframesWriteRotation(body.keyframes)) {
1729
+ stripStudioEditsFromTarget(block.document, body.targetSelector);
1730
+ }
1624
1731
  const script = removeAnimationFromScript(block.scriptText, body.animationId);
1625
1732
  const added = addAnimationWithKeyframesToScript(
1626
1733
  script,
@@ -1704,10 +1811,10 @@ async function executeGsapMutationRecast(body, block, respond) {
1704
1811
  unrollDynamicAnimations: unrollDynamicAnimations2,
1705
1812
  setArcPathInScript: setArcPathInScript2,
1706
1813
  updateArcSegmentInScript: updateArcSegmentInScript2,
1707
- updateMotionPathPointInScript,
1708
- addMotionPathPointInScript,
1709
- removeMotionPathPointInScript,
1710
- addMotionPathToScript,
1814
+ updateMotionPathPointInScript: updateMotionPathPointInScript2,
1815
+ addMotionPathPointInScript: addMotionPathPointInScript2,
1816
+ removeMotionPathPointInScript: removeMotionPathPointInScript2,
1817
+ addMotionPathToScript: addMotionPathToScript2,
1711
1818
  removeArcPathFromScript: removeArcPathFromScript2,
1712
1819
  addAnimationWithKeyframesToScript: addAnimationWithKeyframesToScript2,
1713
1820
  splitAnimationsInScript: splitAnimationsInScript2,
@@ -1904,22 +2011,22 @@ async function executeGsapMutationRecast(body, block, respond) {
1904
2011
  });
1905
2012
  }
1906
2013
  case "update-motion-path-point": {
1907
- return updateMotionPathPointInScript(block.scriptText, body.animationId, body.pointIndex, {
2014
+ return updateMotionPathPointInScript2(block.scriptText, body.animationId, body.pointIndex, {
1908
2015
  x: body.x,
1909
2016
  y: body.y
1910
2017
  });
1911
2018
  }
1912
2019
  case "add-motion-path-point": {
1913
- return addMotionPathPointInScript(block.scriptText, body.animationId, body.index, {
2020
+ return addMotionPathPointInScript2(block.scriptText, body.animationId, body.index, {
1914
2021
  x: body.x,
1915
2022
  y: body.y
1916
2023
  });
1917
2024
  }
1918
2025
  case "remove-motion-path-point": {
1919
- return removeMotionPathPointInScript(block.scriptText, body.animationId, body.index);
2026
+ return removeMotionPathPointInScript2(block.scriptText, body.animationId, body.index);
1920
2027
  }
1921
2028
  case "add-motion-path": {
1922
- const result = addMotionPathToScript(
2029
+ const result = addMotionPathToScript2(
1923
2030
  block.scriptText,
1924
2031
  body.targetSelector,
1925
2032
  body.position,
@@ -1942,7 +2049,8 @@ async function executeGsapMutationRecast(body, block, respond) {
1942
2049
  body.position,
1943
2050
  body.duration,
1944
2051
  body.keyframes,
1945
- body.ease
2052
+ body.ease,
2053
+ body.easeEach
1946
2054
  );
1947
2055
  return result.script;
1948
2056
  }
@@ -2019,7 +2127,7 @@ async function executeGsapMutationRecast(body, block, respond) {
2019
2127
  return respond({ error: `unknown mutation type: ${body.type}` }, 400);
2020
2128
  }
2021
2129
  }
2022
- async function foldAtomicCutFile(c, file, absPath, before) {
2130
+ async function foldAtomicCutFile(c, file, absPath, before, writer) {
2023
2131
  let after = before;
2024
2132
  let splitCount = 0;
2025
2133
  const skippedSelectors = /* @__PURE__ */ new Set();
@@ -2065,7 +2173,8 @@ async function foldAtomicCutFile(c, file, absPath, before) {
2065
2173
  elementDuration: cut.elementDuration
2066
2174
  },
2067
2175
  block,
2068
- respond
2176
+ respond,
2177
+ writer
2069
2178
  );
2070
2179
  if (result instanceof Response) return result;
2071
2180
  let script = typeof result === "string" ? result : result.script;
@@ -2073,8 +2182,7 @@ async function foldAtomicCutFile(c, file, absPath, before) {
2073
2182
  for (const selector of result.skippedSelectors) skippedSelectors.add(selector);
2074
2183
  }
2075
2184
  if (script !== block.scriptText) {
2076
- const parser = await loadGsapParser();
2077
- script = parser.syncPositionHoldsBeforeKeyframes(script);
2185
+ script = writer === "acorn" ? syncPositionHoldsBeforeKeyframes(script) : (await loadGsapParser()).syncPositionHoldsBeforeKeyframes(script);
2078
2186
  after = block.replaceScript(script);
2079
2187
  }
2080
2188
  }
@@ -2364,6 +2472,14 @@ function registerFileRoutes(api, adapter) {
2364
2472
  const files = body.files;
2365
2473
  const project = await adapter.resolveProject(c.req.param("id"));
2366
2474
  if (!project) return c.json({ error: "not found" }, 404);
2475
+ let writer;
2476
+ try {
2477
+ writer = resolveGsapWriter({
2478
+ HYPERFRAMES_GSAP_WRITER: process.env["HYPERFRAMES_GSAP_WRITER"]
2479
+ });
2480
+ } catch (error) {
2481
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
2482
+ }
2367
2483
  return serializeAtomicCut(async () => {
2368
2484
  const seen = /* @__PURE__ */ new Set();
2369
2485
  const prepared = [];
@@ -2392,7 +2508,7 @@ function registerFileRoutes(api, adapter) {
2392
2508
  }
2393
2509
  let folded;
2394
2510
  try {
2395
- folded = await foldAtomicCutFile(c, file, absPath, before);
2511
+ folded = await foldAtomicCutFile(c, file, absPath, before, writer);
2396
2512
  } catch (error) {
2397
2513
  const message = error instanceof Error ? error.message : "Cut transform failed";
2398
2514
  return c.json({ error: message }, 400);