@hyperframes/studio-server 0.8.127 → 0.8.129

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.js CHANGED
@@ -47,7 +47,7 @@ import {
47
47
  resolveProjectAndSignature,
48
48
  resolveProjectSignature,
49
49
  settledFileTag
50
- } from "./chunk-HY2KCPIA.js";
50
+ } from "./chunk-36F5I56K.js";
51
51
  import {
52
52
  clearElementScreenshotIsolation,
53
53
  getElementScreenshotClip
@@ -595,8 +595,7 @@ import {
595
595
  replaceTweenWithKeyframesInScript,
596
596
  splitAnimationsInScript,
597
597
  splitIntoPropertyGroupsFromScript,
598
- shiftPositionsInScript,
599
- scalePositionsInScript,
598
+ retimeClipTweensInScript,
600
599
  dedupePositionWritesInScript,
601
600
  syncPositionHoldsBeforeKeyframes,
602
601
  clipQueryRoot
@@ -1600,6 +1599,38 @@ ${bootstrap}`;
1600
1599
  if (!block) return c.json({ error: "no GSAP script found in file" }, 400);
1601
1600
  return { html, beforeHtml, block };
1602
1601
  }
1602
+ function retimeRuns(mutations) {
1603
+ const runs = /* @__PURE__ */ new Map();
1604
+ let start = -1;
1605
+ mutations.forEach((mutation, index) => {
1606
+ const retime = clipRetimeOf(mutation);
1607
+ if (!retime) return void (start = -1);
1608
+ if (start < 0) runs.set(start = index, []);
1609
+ runs.get(start).push(retime);
1610
+ });
1611
+ return runs;
1612
+ }
1613
+ function clipRetimeOf(mutation) {
1614
+ if (mutation.type === "shift-positions") {
1615
+ const { targetSelector: targetSelector2, delta } = mutation;
1616
+ return targetSelector2 && Number.isFinite(delta) && delta !== 0 ? { kind: "shift", targetSelector: targetSelector2, delta } : "no-op";
1617
+ }
1618
+ if (mutation.type !== "scale-positions") return null;
1619
+ const { targetSelector, oldStart, oldDuration, newStart, newDuration } = mutation;
1620
+ const finite = [oldStart, oldDuration, newStart, newDuration].every(Number.isFinite);
1621
+ if (!targetSelector || !finite || oldDuration <= 0 || newDuration <= 0) return "no-op";
1622
+ if (oldStart === newStart && oldDuration === newDuration) return "no-op";
1623
+ return { kind: "scale", targetSelector, oldStart, oldDuration, newStart, newDuration };
1624
+ }
1625
+ function retimeRun(script, run, root) {
1626
+ const live = run.filter((slot) => slot !== "no-op");
1627
+ const retimed = retimeClipTweensInScript(script, live, root);
1628
+ const synced = syncPositionHoldsBeforeKeyframes(retimed.script);
1629
+ let next = 0;
1630
+ const changed = run.map((slot) => slot !== "no-op" && retimed.changed[next++]);
1631
+ if (synced !== retimed.script) changed[changed.length - 1] = true;
1632
+ return { script: synced, changed: synced === script ? changed.map(() => false) : changed };
1633
+ }
1603
1634
  async function applyGsapMutations(c, res, mutations) {
1604
1635
  const firstMutation = mutations[0];
1605
1636
  if (!firstMutation) return c.json({ error: "mutations array required" }, 400);
@@ -1618,7 +1649,17 @@ async function applyGsapMutations(c, res, mutations) {
1618
1649
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
1619
1650
  }
1620
1651
  const mutationChanges = [];
1621
- for (const mutation of mutations) {
1652
+ const retimes = writer === "acorn" ? retimeRuns(mutations) : /* @__PURE__ */ new Map();
1653
+ for (let index = 0; index < mutations.length; index++) {
1654
+ const run = retimes.get(index);
1655
+ if (run) {
1656
+ const retimed = retimeRun(block.scriptText, run, block.root);
1657
+ mutationChanges.push(...retimed.changed);
1658
+ block.scriptText = retimed.script;
1659
+ index += run.length - 1;
1660
+ continue;
1661
+ }
1662
+ const mutation = mutations[index];
1622
1663
  const previousScript = block.scriptText;
1623
1664
  const result = await executeGsapMutation(mutation, block, respond, writer);
1624
1665
  if (result instanceof Response) return result;
@@ -1930,33 +1971,14 @@ function executeGsapMutationAcorn(body, block, respond) {
1930
1971
  case "unroll-timeline": {
1931
1972
  return unrollComputedTimeline(block.scriptText);
1932
1973
  }
1933
- case "shift-positions": {
1934
- const { targetSelector, delta } = body;
1935
- if (!targetSelector || !Number.isFinite(delta) || delta === 0) return block.scriptText;
1936
- return shiftPositionsInScript(block.scriptText, targetSelector, delta, block.root);
1937
- }
1938
1974
  case "shift-positions-batch": {
1939
- let script = block.scriptText;
1940
- for (const s of body.shifts) {
1941
- if (!s.targetSelector || !Number.isFinite(s.delta) || s.delta === 0) continue;
1942
- script = shiftPositionsInScript(script, s.targetSelector, s.delta, block.root);
1943
- }
1944
- return script;
1975
+ const shifts = body.shifts.filter((s) => s.targetSelector && Number.isFinite(s.delta) && s.delta !== 0).map((s) => ({ kind: "shift", targetSelector: s.targetSelector, delta: s.delta }));
1976
+ return retimeClipTweensInScript(block.scriptText, shifts, block.root).script;
1945
1977
  }
1978
+ case "shift-positions":
1946
1979
  case "scale-positions": {
1947
- const { targetSelector, oldStart, oldDuration, newStart, newDuration } = body;
1948
- if (!targetSelector || !Number.isFinite(oldStart) || !Number.isFinite(oldDuration) || !Number.isFinite(newStart) || !Number.isFinite(newDuration) || oldDuration <= 0 || newDuration <= 0)
1949
- return block.scriptText;
1950
- if (oldStart === newStart && oldDuration === newDuration) return block.scriptText;
1951
- return scalePositionsInScript(
1952
- block.scriptText,
1953
- targetSelector,
1954
- oldStart,
1955
- oldDuration,
1956
- newStart,
1957
- newDuration,
1958
- block.root
1959
- );
1980
+ const retime = clipRetimeOf(body);
1981
+ return retime && retime !== "no-op" ? retimeClipTweensInScript(block.scriptText, [retime], block.root).script : block.scriptText;
1960
1982
  }
1961
1983
  default:
1962
1984
  return respond({ error: `unknown mutation type: ${body.type}` }, 400);
@@ -2255,15 +2277,15 @@ async function executeGsapMutationRecast(body, block, respond) {
2255
2277
  case "shift-positions": {
2256
2278
  const { targetSelector, delta } = body;
2257
2279
  if (!targetSelector || !Number.isFinite(delta) || delta === 0) return block.scriptText;
2258
- const { shiftPositionsInScript: shiftPositionsInScript2 } = parser;
2259
- return shiftPositionsInScript2(block.scriptText, targetSelector, delta, block.root);
2280
+ const { shiftPositionsInScript } = parser;
2281
+ return shiftPositionsInScript(block.scriptText, targetSelector, delta, block.root);
2260
2282
  }
2261
2283
  case "shift-positions-batch": {
2262
- const { shiftPositionsInScript: shiftPositionsInScript2 } = parser;
2284
+ const { shiftPositionsInScript } = parser;
2263
2285
  let script = block.scriptText;
2264
2286
  for (const s of body.shifts) {
2265
2287
  if (!s.targetSelector || !Number.isFinite(s.delta) || s.delta === 0) continue;
2266
- script = shiftPositionsInScript2(script, s.targetSelector, s.delta, block.root);
2288
+ script = shiftPositionsInScript(script, s.targetSelector, s.delta, block.root);
2267
2289
  }
2268
2290
  return script;
2269
2291
  }
@@ -2272,8 +2294,8 @@ async function executeGsapMutationRecast(body, block, respond) {
2272
2294
  if (!targetSelector || !Number.isFinite(oldStart) || !Number.isFinite(oldDuration) || !Number.isFinite(newStart) || !Number.isFinite(newDuration) || oldDuration <= 0 || newDuration <= 0)
2273
2295
  return block.scriptText;
2274
2296
  if (oldStart === newStart && oldDuration === newDuration) return block.scriptText;
2275
- const { scalePositionsInScript: scalePositionsInScript2 } = parser;
2276
- return scalePositionsInScript2(
2297
+ const { scalePositionsInScript } = parser;
2298
+ return scalePositionsInScript(
2277
2299
  block.scriptText,
2278
2300
  targetSelector,
2279
2301
  oldStart,
@@ -6174,6 +6196,12 @@ function createStudioApi(adapter) {
6174
6196
  const project = await Promise.resolve().then(() => adapter.resolveProject(c.req.param("id"))).catch(() => null);
6175
6197
  if (project) adapter.invalidateProjectSignature?.(project.dir);
6176
6198
  });
6199
+ api.use("/projects/:id/*", async function openHistorySoNoWriteBecomesItsBaseline(c, next) {
6200
+ if (c.req.method !== "GET" && c.req.method !== "HEAD" && adapter.history) {
6201
+ await Promise.resolve().then(() => adapter.resolveProject(c.req.param("id"))).then((project) => project && adapter.history?.(project)).catch(() => null);
6202
+ }
6203
+ await next();
6204
+ });
6177
6205
  registerProjectRoutes(api, adapter);
6178
6206
  registerFileRoutes(api, adapter);
6179
6207
  registerPreviewRoutes(api, adapter);