hyperframes 0.7.18 → 0.7.19

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/cli.js CHANGED
@@ -50,7 +50,7 @@ var VERSION;
50
50
  var init_version = __esm({
51
51
  "src/version.ts"() {
52
52
  "use strict";
53
- VERSION = true ? "0.7.18" : "0.0.0-dev";
53
+ VERSION = true ? "0.7.19" : "0.0.0-dev";
54
54
  }
55
55
  });
56
56
 
@@ -53193,20 +53193,23 @@ function findEnclosingExpressionStatement(ancestors) {
53193
53193
  }
53194
53194
  return null;
53195
53195
  }
53196
- function removeAnimationFromScript(script, animationId) {
53197
- const parsed = parseGsapScriptAcornForWrite(script);
53198
- if (!parsed) return script;
53199
- const target = parsed.located.find((l) => l.id === animationId);
53200
- if (!target) return script;
53201
- const ms = new MagicString(script);
53202
- const N2 = target.call.node;
53203
- const exprStmt = findEnclosingExpressionStatement(target.call.ancestors);
53196
+ function removeCallFromMagicString(ms, call, script) {
53197
+ const N2 = call.node;
53198
+ const exprStmt = findEnclosingExpressionStatement(call.ancestors);
53204
53199
  if (N2.callee?.object?.type !== "CallExpression" && exprStmt?.expression === N2) {
53205
53200
  const end = exprStmt.end < script.length && script[exprStmt.end] === "\n" ? exprStmt.end + 1 : exprStmt.end;
53206
53201
  ms.remove(exprStmt.start, end);
53207
53202
  } else {
53208
53203
  ms.remove(N2.callee.object.end, N2.end);
53209
53204
  }
53205
+ }
53206
+ function removeAnimationFromScript(script, animationId) {
53207
+ const parsed = parseGsapScriptAcornForWrite(script);
53208
+ if (!parsed) return script;
53209
+ const target = parsed.located.find((l) => l.id === animationId);
53210
+ if (!target) return script;
53211
+ const ms = new MagicString(script);
53212
+ removeCallFromMagicString(ms, target.call, script);
53210
53213
  return ms.toString();
53211
53214
  }
53212
53215
  function getElementType(el) {
@@ -79532,26 +79535,30 @@ function studioSelectionUrl(server) {
79532
79535
  return studioApiUrl(server, "selection");
79533
79536
  }
79534
79537
  function studioApiUrl(server, route) {
79535
- return `http://127.0.0.1:${server.port}/api/projects/${encodeURIComponent(server.projectName)}/${route}`;
79538
+ const host = server.host ?? "127.0.0.1";
79539
+ return `http://${host}:${server.port}/api/projects/${encodeURIComponent(server.projectName)}/${route}`;
79536
79540
  }
79537
79541
  async function findViteStudioServerForProject(normalizedProjectDir, fetchImpl, ports = VITE_STUDIO_DISCOVERY_PORTS) {
79538
79542
  for (const port of ports) {
79539
- try {
79540
- const response = await fetchImpl(`http://127.0.0.1:${port}/api/projects`);
79541
- if (!response.ok) continue;
79542
- const payload = await response.json();
79543
- const project = payload.projects?.find(
79544
- (candidate) => normalizePath(candidate.dir) === normalizedProjectDir
79545
- );
79546
- if (!project) continue;
79547
- return {
79548
- port,
79549
- projectName: project.id,
79550
- projectDir: project.dir,
79551
- version: "studio-dev",
79552
- pid: null
79553
- };
79554
- } catch {
79543
+ for (const host of LOOPBACK_HOSTS) {
79544
+ try {
79545
+ const response = await fetchImpl(`http://${host}:${port}/api/projects`);
79546
+ if (!response.ok) continue;
79547
+ const payload = await response.json();
79548
+ const project = payload.projects?.find(
79549
+ (candidate) => normalizePath(candidate.dir) === normalizedProjectDir
79550
+ );
79551
+ if (!project) continue;
79552
+ return {
79553
+ port,
79554
+ host,
79555
+ projectName: project.id,
79556
+ projectDir: project.dir,
79557
+ version: "studio-dev",
79558
+ pid: null
79559
+ };
79560
+ } catch {
79561
+ }
79555
79562
  }
79556
79563
  }
79557
79564
  return null;
@@ -79572,7 +79579,7 @@ async function fetchStudioLint(server, fetchImpl = fetch) {
79572
79579
  }
79573
79580
  return await response.json();
79574
79581
  }
79575
- var VITE_STUDIO_DISCOVERY_PORTS, AmbiguousPreviewServerError, PreviewServerPortMismatchError;
79582
+ var VITE_STUDIO_DISCOVERY_PORTS, AmbiguousPreviewServerError, PreviewServerPortMismatchError, LOOPBACK_HOSTS;
79576
79583
  var init_studioSelectionClient = __esm({
79577
79584
  "src/utils/studioSelectionClient.ts"() {
79578
79585
  "use strict";
@@ -79602,6 +79609,7 @@ var init_studioSelectionClient = __esm({
79602
79609
  this.ports = ports;
79603
79610
  }
79604
79611
  };
79612
+ LOOPBACK_HOSTS = ["127.0.0.1", "[::1]"];
79605
79613
  }
79606
79614
  });
79607
79615
 
@@ -81315,19 +81323,37 @@ function addAnimationToScript(script, animation) {
81315
81323
  const newId = reParsed?.located[reParsed.located.length - 1]?.id ?? "";
81316
81324
  return { script: result, id: newId };
81317
81325
  }
81326
+ function removeCallFromMagicString2(ms, call, script) {
81327
+ const N2 = call.node;
81328
+ const exprStmt = findEnclosingExpressionStatement2(call.ancestors);
81329
+ if (N2.callee?.object?.type !== "CallExpression" && exprStmt?.expression === N2) {
81330
+ const end = exprStmt.end < script.length && script[exprStmt.end] === "\n" ? exprStmt.end + 1 : exprStmt.end;
81331
+ ms.remove(exprStmt.start, end);
81332
+ } else {
81333
+ ms.remove(N2.callee.object.end, N2.end);
81334
+ }
81335
+ }
81318
81336
  function removeAnimationFromScript2(script, animationId) {
81319
81337
  const parsed = parseGsapScriptAcornForWrite3(script);
81320
81338
  if (!parsed) return script;
81321
81339
  const target = parsed.located.find((l) => l.id === animationId);
81322
81340
  if (!target) return script;
81323
81341
  const ms = new MagicString(script);
81324
- const N2 = target.call.node;
81325
- const exprStmt = findEnclosingExpressionStatement2(target.call.ancestors);
81326
- if (N2.callee?.object?.type !== "CallExpression" && exprStmt?.expression === N2) {
81327
- const end = exprStmt.end < script.length && script[exprStmt.end] === "\n" ? exprStmt.end + 1 : exprStmt.end;
81328
- ms.remove(exprStmt.start, end);
81329
- } else {
81330
- ms.remove(N2.callee.object.end, N2.end);
81342
+ removeCallFromMagicString2(ms, target.call, script);
81343
+ return ms.toString();
81344
+ }
81345
+ function dedupePositionWritesInScript(script, selector, keepId) {
81346
+ const parsed = parseGsapScriptAcornForWrite3(script);
81347
+ if (!parsed) return script;
81348
+ const posWrites = parsed.located.filter(
81349
+ (l) => l.animation.targetSelector === selector && l.animation.propertyGroup === "position"
81350
+ );
81351
+ if (posWrites.length <= 1) return script;
81352
+ const keeper = posWrites.find((l) => l.id === keepId) ?? posWrites[posWrites.length - 1];
81353
+ const ms = new MagicString(script);
81354
+ for (const l of posWrites) {
81355
+ if (l === keeper) continue;
81356
+ removeCallFromMagicString2(ms, l.call, script);
81331
81357
  }
81332
81358
  return ms.toString();
81333
81359
  }
@@ -81698,6 +81724,50 @@ function removeKeyframeFromScript(script, animationId, percentage) {
81698
81724
  removeProp(ms, match.prop, allProps);
81699
81725
  return ms.toString();
81700
81726
  }
81727
+ function moveKeyframeInScript(script, animationId, fromPercentage, toPercentage) {
81728
+ const located = locateWithKeyframes(script, animationId);
81729
+ if (!located) return script;
81730
+ const { kfNode } = located;
81731
+ const match = findKfPropByPct(kfNode, fromPercentage);
81732
+ if (!match) return script;
81733
+ if (Math.abs(fromPercentage - toPercentage) < MOVE_NOOP_EPSILON_PCT) return script;
81734
+ const dest = findKfPropByPct(kfNode, toPercentage);
81735
+ const collision = dest && dest.prop !== match.prop ? dest : null;
81736
+ const entries2 = [];
81737
+ for (const prop2 of percentagePropsOf(kfNode)) {
81738
+ if (prop2 === match.prop) continue;
81739
+ if (collision && prop2 === collision.prop) continue;
81740
+ const pct = percentageFromKey(propKeyName22(prop2) ?? "");
81741
+ if (Number.isNaN(pct)) continue;
81742
+ entries2.push({ pct, record: valueNodeToRecord(prop2.value, script) });
81743
+ }
81744
+ entries2.push({ pct: toPercentage, record: valueNodeToRecord(match.prop.value, script) });
81745
+ entries2.sort((a, b2) => a.pct - b2.pct);
81746
+ const body = entries2.map((e3) => `${JSON.stringify(`${e3.pct}%`)}: ${recordToCode(e3.record)}`).join(", ");
81747
+ const ms = new MagicString(script);
81748
+ ms.overwrite(kfNode.start, kfNode.end, `{ ${body} }`);
81749
+ return ms.toString();
81750
+ }
81751
+ function resizeKeyframedTweenInScript(script, animationId, newPosition, newDuration, pctRemap) {
81752
+ const located = locateWithKeyframes(script, animationId);
81753
+ if (!located) return script;
81754
+ const { target, kfNode } = located;
81755
+ const edits = [];
81756
+ const seen = /* @__PURE__ */ new Set();
81757
+ for (const { from, to } of pctRemap) {
81758
+ const match = findKfPropByPct(kfNode, from);
81759
+ if (!match || seen.has(match.prop.key)) continue;
81760
+ seen.add(match.prop.key);
81761
+ edits.push({ keyNode: match.prop.key, to });
81762
+ }
81763
+ const ms = new MagicString(script);
81764
+ for (const { keyNode, to } of edits) {
81765
+ ms.overwrite(keyNode.start, keyNode.end, JSON.stringify(`${to}%`));
81766
+ }
81767
+ overwritePosition(ms, target.call, newPosition);
81768
+ upsertProp(ms, target.call.varsArg, "duration", newDuration);
81769
+ return ms.toString();
81770
+ }
81701
81771
  function removeAllKeyframesFromScript(script, animationId) {
81702
81772
  const parsed = parseGsapScriptAcornForWrite3(script);
81703
81773
  if (!parsed) return script;
@@ -81714,6 +81784,14 @@ function removeAllKeyframesFromScript(script, animationId) {
81714
81784
  target.call,
81715
81785
  buildVarsObjectCode(buildCollapsedFlatVars(target.animation, collapse))
81716
81786
  );
81787
+ if (target.animation.propertyGroup === "position") {
81788
+ for (const l of parsed.located) {
81789
+ if (l === target) continue;
81790
+ if (l.animation.targetSelector === target.animation.targetSelector && l.animation.propertyGroup === "position") {
81791
+ removeCallFromMagicString2(ms, l.call, script);
81792
+ }
81793
+ }
81794
+ }
81717
81795
  return ms.toString();
81718
81796
  }
81719
81797
  function buildCollapsedFlatVars(animation, collapse) {
@@ -81721,11 +81799,11 @@ function buildCollapsedFlatVars(animation, collapse) {
81721
81799
  for (const [k2, v2] of Object.entries(collapse.properties)) {
81722
81800
  if (k2 !== "ease") flat[k2] = v2;
81723
81801
  }
81724
- if (animation.duration !== void 0) flat.duration = animation.duration;
81725
- if (animation.ease) flat.ease = animation.ease;
81726
81802
  for (const [k2, v2] of Object.entries(animation.extras ?? {})) {
81727
81803
  if (typeof v2 === "number" || typeof v2 === "string") flat[k2] = v2;
81728
81804
  }
81805
+ flat.duration = 0;
81806
+ flat.immediateRender = true;
81729
81807
  return flat;
81730
81808
  }
81731
81809
  function buildKeyframesVarsCode(animation, fromProps, toProps, varsNode, source, setDuration) {
@@ -82392,7 +82470,7 @@ function unrollDynamicAnimations(script, animationId, elements) {
82392
82470
  }
82393
82471
  return ms.toString();
82394
82472
  }
82395
- var PROPERTY_GROUPS4, PROP_TO_GROUP4, CSS_IDENTITY, GSAP_METHODS4, QUERY_METHODS3, ITERATION_METHODS3, SCOPE_NODE_TYPES3, BUILTIN_VAR_KEYS3, DROPPED_VAR_KEYS3, EXTRAS_KEYS3, PERCENTAGE_KEY_RE3, GSAP_DEFAULT_DURATION3, NON_EDITABLE_PROP_KEYS, CSS_IDENTITY2, NON_EDITABLE_VAR_KEYS, PERCENTAGE_KEY_RE22, PCT_TOLERANCE, LITERAL_NODE_TYPES, REFUSE_UNROLL;
82473
+ var PROPERTY_GROUPS4, PROP_TO_GROUP4, CSS_IDENTITY, GSAP_METHODS4, QUERY_METHODS3, ITERATION_METHODS3, SCOPE_NODE_TYPES3, BUILTIN_VAR_KEYS3, DROPPED_VAR_KEYS3, EXTRAS_KEYS3, PERCENTAGE_KEY_RE3, GSAP_DEFAULT_DURATION3, NON_EDITABLE_PROP_KEYS, CSS_IDENTITY2, NON_EDITABLE_VAR_KEYS, PERCENTAGE_KEY_RE22, PCT_TOLERANCE, MOVE_NOOP_EPSILON_PCT, LITERAL_NODE_TYPES, REFUSE_UNROLL;
82396
82474
  var init_gsapWriterAcorn = __esm({
82397
82475
  "../parsers/dist/gsapWriterAcorn.js"() {
82398
82476
  "use strict";
@@ -82481,6 +82559,7 @@ var init_gsapWriterAcorn = __esm({
82481
82559
  ]);
82482
82560
  PERCENTAGE_KEY_RE22 = /^(\d+(?:\.\d+)?)%$/;
82483
82561
  PCT_TOLERANCE = 2;
82562
+ MOVE_NOOP_EPSILON_PCT = 0.05;
82484
82563
  LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["Literal", "NumericLiteral", "StringLiteral"]);
82485
82564
  REFUSE_UNROLL = /* @__PURE__ */ Symbol("refuse-unroll");
82486
82565
  }
@@ -86657,18 +86736,21 @@ __export(gsapParser_exports, {
86657
86736
  classifyPropertyGroup: () => classifyPropertyGroup5,
86658
86737
  classifyTweenPropertyGroup: () => classifyTweenPropertyGroup4,
86659
86738
  convertToKeyframesInScript: () => convertToKeyframesInScript,
86739
+ dedupePositionWritesInScript: () => dedupePositionWritesInScript2,
86660
86740
  generateSpringEaseData: () => generateSpringEaseData,
86661
86741
  getAnimationsForElementId: () => getAnimationsForElementId2,
86662
86742
  gsapAnimationsToKeyframes: () => gsapAnimationsToKeyframes2,
86663
86743
  isStudioHoldSet: () => isStudioHoldSet,
86664
86744
  keyframesToGsapAnimations: () => keyframesToGsapAnimations2,
86665
86745
  materializeKeyframesInScript: () => materializeKeyframesInScript,
86746
+ moveKeyframeInScript: () => moveKeyframeInScript2,
86666
86747
  parseGsapScript: () => parseGsapScript,
86667
86748
  removeAllKeyframesFromScript: () => removeAllKeyframesFromScript2,
86668
86749
  removeAnimationFromScript: () => removeAnimationFromScript3,
86669
86750
  removeArcPathFromScript: () => removeArcPathFromScript2,
86670
86751
  removeKeyframeFromScript: () => removeKeyframeFromScript2,
86671
86752
  removeMotionPathPointInScript: () => removeMotionPathPointInScript,
86753
+ resizeKeyframedTweenInScript: () => resizeKeyframedTweenInScript2,
86672
86754
  scalePositionsInScript: () => scalePositionsInScript2,
86673
86755
  serializeGsapAnimations: () => serializeGsapAnimations2,
86674
86756
  setArcPathInScript: () => setArcPathInScript2,
@@ -88004,9 +88086,13 @@ function removeAnimationFromScript3(script, animationId) {
88004
88086
  target = parsed.located.find((l) => l.id === convertedId);
88005
88087
  }
88006
88088
  if (!target) return script;
88007
- const node = target.call.node;
88008
- const stmtPath = findStatementPath(target.call.path);
88009
- if (!stmtPath) return script;
88089
+ removeCallFromAst(target.call);
88090
+ return recast2.print(parsed.ast).code;
88091
+ }
88092
+ function removeCallFromAst(call) {
88093
+ const node = call.node;
88094
+ const stmtPath = findStatementPath(call.path);
88095
+ if (!stmtPath) return;
88010
88096
  const parentCall = findChainParentCall(stmtPath.node, node);
88011
88097
  if (parentCall) {
88012
88098
  parentCall.callee.object = node.callee.object;
@@ -88015,6 +88101,23 @@ function removeAnimationFromScript3(script, animationId) {
88015
88101
  } else {
88016
88102
  stmtPath.prune();
88017
88103
  }
88104
+ }
88105
+ function dedupePositionWritesInScript2(script, selector, keepId) {
88106
+ let parsed;
88107
+ try {
88108
+ parsed = parseGsapAst(script);
88109
+ } catch {
88110
+ return script;
88111
+ }
88112
+ const posWrites = parsed.located.filter(
88113
+ (l) => l.animation.targetSelector === selector && l.animation.propertyGroup === "position"
88114
+ );
88115
+ if (posWrites.length <= 1) return script;
88116
+ const keeper = posWrites.find((l) => l.id === keepId) ?? posWrites[posWrites.length - 1];
88117
+ for (const l of posWrites) {
88118
+ if (l === keeper) continue;
88119
+ removeCallFromAst(l.call);
88120
+ }
88018
88121
  return recast2.print(parsed.ast).code;
88019
88122
  }
88020
88123
  function insertInheritedStateSet(script, selector, position, properties) {
@@ -88428,6 +88531,49 @@ function removeKeyframeFromScript2(script, animationId, percentage) {
88428
88531
  }
88429
88532
  return recast2.print(loc.parsed.ast).code;
88430
88533
  }
88534
+ function moveKeyframeInScript2(script, animationId, fromPercentage, toPercentage) {
88535
+ const loc = locateAnimationWithFallback(script, animationId);
88536
+ if (!loc) return script;
88537
+ const kfNode = findKeyframesObjectNode(loc.target.call.varsArg);
88538
+ if (!kfNode) return script;
88539
+ const match = findKeyframePropByPct(kfNode, fromPercentage);
88540
+ if (!match) return script;
88541
+ if (Math.abs(fromPercentage - toPercentage) < MOVE_NOOP_EPSILON_PCT2) return script;
88542
+ const dest = findKeyframePropByPct(kfNode, toPercentage);
88543
+ const collision = dest && dest.prop !== match.prop ? dest : null;
88544
+ const movedValue = match.prop.value;
88545
+ const entries2 = [];
88546
+ for (const prop2 of filterPercentageProps(kfNode)) {
88547
+ if (prop2 === match.prop) continue;
88548
+ if (collision && prop2 === collision.prop) continue;
88549
+ const pct = percentageFromKey2(propKeyName4(prop2) ?? "");
88550
+ if (Number.isNaN(pct)) continue;
88551
+ entries2.push({ pct, value: prop2.value });
88552
+ }
88553
+ entries2.push({ pct: toPercentage, value: movedValue });
88554
+ entries2.sort((a, b2) => a.pct - b2.pct);
88555
+ kfNode.properties = entries2.map((e3) => {
88556
+ const p2 = parseExpr(`{ ${JSON.stringify(`${e3.pct}%`)}: {} }`).properties[0];
88557
+ p2.value = e3.value;
88558
+ return p2;
88559
+ });
88560
+ return recast2.print(loc.parsed.ast).code;
88561
+ }
88562
+ function resizeKeyframedTweenInScript2(script, animationId, newPosition, newDuration, pctRemap) {
88563
+ const loc = locateAnimationWithFallback(script, animationId);
88564
+ if (!loc) return script;
88565
+ const kfNode = findKeyframesObjectNode(loc.target.call.varsArg);
88566
+ if (!kfNode) return script;
88567
+ const seen = /* @__PURE__ */ new Set();
88568
+ for (const { from, to } of pctRemap) {
88569
+ const match = findKeyframePropByPct(kfNode, from);
88570
+ if (!match || seen.has(match.prop)) continue;
88571
+ seen.add(match.prop);
88572
+ match.prop.key = parseExpr(`{ ${JSON.stringify(`${to}%`)}: 0 }`).properties[0].key;
88573
+ }
88574
+ applyUpdatesToCall(loc.target.call, { position: newPosition, duration: newDuration });
88575
+ return recast2.print(loc.parsed.ast).code;
88576
+ }
88431
88577
  function updateKeyframeInScript2(script, animationId, percentage, properties, ease) {
88432
88578
  const arrLoc = locateAnimationWithFallback(script, animationId);
88433
88579
  const arrVal = arrLoc && findPropertyNode4(arrLoc.target.call.varsArg, "keyframes");
@@ -88550,6 +88696,17 @@ function removeAllKeyframesFromScript2(script, animationId) {
88550
88696
  const collapseEntry = method === "from" ? kfEntries[0] : kfEntries[kfEntries.length - 1];
88551
88697
  const record = objectExpressionToRecord4(collapseEntry.prop.value, loc.parsed.scope);
88552
88698
  collapseKeyframesToFlat2(loc.target.call.varsArg, record);
88699
+ removeVarsKey(loc.target.call.varsArg, "ease");
88700
+ setVarsKey(loc.target.call.varsArg, "duration", 0);
88701
+ setVarsKey(loc.target.call.varsArg, "immediateRender", true);
88702
+ if (loc.target.animation.propertyGroup === "position") {
88703
+ for (const l of loc.parsed.located) {
88704
+ if (l === loc.target) continue;
88705
+ if (l.animation.targetSelector === loc.target.animation.targetSelector && l.animation.propertyGroup === "position") {
88706
+ removeCallFromAst(l.call);
88707
+ }
88708
+ }
88709
+ }
88553
88710
  return recast2.print(loc.parsed.ast).code;
88554
88711
  }
88555
88712
  function materializeKeyframesInScript(script, animationId, keyframes, easeEach, resolvedSelector) {
@@ -88971,7 +89128,7 @@ function unrollDynamicAnimations2(script, animationId, elements) {
88971
89128
  }
88972
89129
  return script;
88973
89130
  }
88974
- var recast2, import_parser3, SUPPORTED_PROPS, PROPERTY_GROUPS5, PROP_TO_GROUP5, SUPPORTED_EASES, FORBIDDEN_GSAP_PATTERNS2, CSS_IDENTITY3, SPRING_PRESETS, GSAP_METHODS5, QUERY_METHODS4, ITERATION_METHODS4, SCOPE_NODE_TYPES4, BUILTIN_VAR_KEYS4, DROPPED_VAR_KEYS4, EXTRAS_KEYS4, PERCENTAGE_KEY_RE4, GSAP_DEFAULT_DURATION4, STUDIO_HOLD_MARKER, PCT_TOLERANCE2, ANIM_ID_RE;
89131
+ var recast2, import_parser3, SUPPORTED_PROPS, PROPERTY_GROUPS5, PROP_TO_GROUP5, SUPPORTED_EASES, FORBIDDEN_GSAP_PATTERNS2, CSS_IDENTITY3, SPRING_PRESETS, GSAP_METHODS5, QUERY_METHODS4, ITERATION_METHODS4, SCOPE_NODE_TYPES4, BUILTIN_VAR_KEYS4, DROPPED_VAR_KEYS4, EXTRAS_KEYS4, PERCENTAGE_KEY_RE4, GSAP_DEFAULT_DURATION4, STUDIO_HOLD_MARKER, PCT_TOLERANCE2, MOVE_NOOP_EPSILON_PCT2, ANIM_ID_RE;
88975
89132
  var init_gsapParser = __esm({
88976
89133
  "../parsers/dist/gsapParser.js"() {
88977
89134
  "use strict";
@@ -89119,6 +89276,7 @@ var init_gsapParser = __esm({
89119
89276
  GSAP_DEFAULT_DURATION4 = 0.5;
89120
89277
  STUDIO_HOLD_MARKER = "hf-hold";
89121
89278
  PCT_TOLERANCE2 = 2;
89279
+ MOVE_NOOP_EPSILON_PCT2 = 0.05;
89122
89280
  ANIM_ID_RE = /^(.*)-(fromTo|from|to|set)-(\d+)-([a-z]+)$/;
89123
89281
  }
89124
89282
  });
@@ -90276,6 +90434,14 @@ function executeGsapMutationAcorn(body, block, respond2) {
90276
90434
  }
90277
90435
  return script;
90278
90436
  }
90437
+ case "consolidate-position-writes": {
90438
+ if (!body.targetSelector) return block.scriptText;
90439
+ return dedupePositionWritesInScript(
90440
+ block.scriptText,
90441
+ body.targetSelector,
90442
+ body.keepAnimationId
90443
+ );
90444
+ }
90279
90445
  case "remove-property": {
90280
90446
  const r2 = requireAnimation(block.scriptText, body.animationId);
90281
90447
  if ("err" in r2) return r2.err;
@@ -90307,6 +90473,23 @@ function executeGsapMutationAcorn(body, block, respond2) {
90307
90473
  case "remove-keyframe": {
90308
90474
  return removeKeyframeFromScript(block.scriptText, body.animationId, body.percentage);
90309
90475
  }
90476
+ case "move-keyframe": {
90477
+ return moveKeyframeInScript(
90478
+ block.scriptText,
90479
+ body.animationId,
90480
+ body.fromPercentage,
90481
+ body.toPercentage
90482
+ );
90483
+ }
90484
+ case "resize-keyframed-tween": {
90485
+ return resizeKeyframedTweenInScript(
90486
+ block.scriptText,
90487
+ body.animationId,
90488
+ body.position,
90489
+ body.duration,
90490
+ body.pctRemap
90491
+ );
90492
+ }
90310
90493
  case "update-keyframe": {
90311
90494
  return updateKeyframeInScript(
90312
90495
  block.scriptText,
@@ -90439,6 +90622,8 @@ async function executeGsapMutationRecast(body, block, respond2) {
90439
90622
  removeAnimationFromScript: removeAnimationFromScript22,
90440
90623
  addKeyframeToScript: addKeyframeToScript22,
90441
90624
  removeKeyframeFromScript: removeKeyframeFromScript22,
90625
+ moveKeyframeInScript: moveKeyframeInScript22,
90626
+ resizeKeyframedTweenInScript: resizeKeyframedTweenInScript22,
90442
90627
  updateKeyframeInScript: updateKeyframeInScript22,
90443
90628
  convertToKeyframesInScript: convertToKeyframesInScript2,
90444
90629
  removeAllKeyframesFromScript: removeAllKeyframesFromScript22,
@@ -90453,7 +90638,8 @@ async function executeGsapMutationRecast(body, block, respond2) {
90453
90638
  removeArcPathFromScript: removeArcPathFromScript22,
90454
90639
  addAnimationWithKeyframesToScript: addAnimationWithKeyframesToScript22,
90455
90640
  splitAnimationsInScript: splitAnimationsInScript22,
90456
- splitIntoPropertyGroups: splitIntoPropertyGroups2
90641
+ splitIntoPropertyGroups: splitIntoPropertyGroups2,
90642
+ dedupePositionWritesInScript: dedupePositionWritesInScript22
90457
90643
  } = parser;
90458
90644
  function requireAnimation(scriptText, animationId) {
90459
90645
  const parsed = parseGsapScriptAcorn2(scriptText);
@@ -90538,6 +90724,14 @@ async function executeGsapMutationRecast(body, block, respond2) {
90538
90724
  }
90539
90725
  return script;
90540
90726
  }
90727
+ case "consolidate-position-writes": {
90728
+ if (!body.targetSelector) return block.scriptText;
90729
+ return dedupePositionWritesInScript22(
90730
+ block.scriptText,
90731
+ body.targetSelector,
90732
+ body.keepAnimationId
90733
+ );
90734
+ }
90541
90735
  case "remove-property": {
90542
90736
  const r2 = requireAnimation(block.scriptText, body.animationId);
90543
90737
  if ("err" in r2) return r2.err;
@@ -90569,6 +90763,23 @@ async function executeGsapMutationRecast(body, block, respond2) {
90569
90763
  case "remove-keyframe": {
90570
90764
  return removeKeyframeFromScript22(block.scriptText, body.animationId, body.percentage);
90571
90765
  }
90766
+ case "move-keyframe": {
90767
+ return moveKeyframeInScript22(
90768
+ block.scriptText,
90769
+ body.animationId,
90770
+ body.fromPercentage,
90771
+ body.toPercentage
90772
+ );
90773
+ }
90774
+ case "resize-keyframed-tween": {
90775
+ return resizeKeyframedTweenInScript22(
90776
+ block.scriptText,
90777
+ body.animationId,
90778
+ body.position,
90779
+ body.duration,
90780
+ body.pctRemap
90781
+ );
90782
+ }
90572
90783
  case "update-keyframe": {
90573
90784
  return updateKeyframeInScript22(
90574
90785
  block.scriptText,
@@ -92751,11 +92962,13 @@ function registerThumbnailRoutes(api, adapter2) {
92751
92962
  let compW = vpWidth || 1920;
92752
92963
  let compH = vpHeight || 1080;
92753
92964
  let sourceMtime = 0;
92754
- if (!vpWidth) {
92755
- const htmlFile = join112(project.dir, compPath);
92756
- if (existsSync72(htmlFile)) {
92757
- sourceMtime = Math.round(statSync42(htmlFile).mtimeMs);
92758
- const html = readFileSync102(htmlFile, "utf-8");
92965
+ let sourceKey = "";
92966
+ const htmlFile = join112(project.dir, compPath);
92967
+ if (existsSync72(htmlFile)) {
92968
+ const html = readFileSync102(htmlFile, "utf-8");
92969
+ sourceKey = `_${createHash22("sha1").update(html).digest("hex").slice(0, 16)}`;
92970
+ sourceMtime = Math.round(statSync42(htmlFile).mtimeMs);
92971
+ if (!vpWidth) {
92759
92972
  const wMatch = html.match(/data-width=["'](\d+)["']/);
92760
92973
  const hMatch = html.match(/data-height=["'](\d+)["']/);
92761
92974
  if (wMatch?.[1]) compW = parseInt(wMatch[1]);
@@ -92780,11 +92993,11 @@ function registerThumbnailRoutes(api, adapter2) {
92780
92993
  const cacheDir = join112(project.dir, ".thumbnails");
92781
92994
  const selectorKey = selector ? `_${selector.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 80)}_${selectorIndex ?? 0}` : "";
92782
92995
  const urlVersionKey = urlVersion ? `_${urlVersion.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32)}` : "";
92783
- const cacheKey = `${THUMBNAIL_CACHE_VERSION}${urlVersionKey}${manualEditsKey}${motionKey}_${format}_${compPath.replace(/\//g, "_")}_${compW}x${compH}_${sourceMtime}_${seekTime.toFixed(2)}${selectorKey}.${format === "png" ? "png" : "jpg"}`;
92996
+ const cacheKey = `${THUMBNAIL_CACHE_VERSION}${urlVersionKey}${manualEditsKey}${motionKey}${sourceKey}_${format}_${compPath.replace(/\//g, "_")}_${compW}x${compH}_${sourceMtime}_${seekTime.toFixed(2)}${selectorKey}.${format === "png" ? "png" : "jpg"}`;
92784
92997
  const cachePath2 = join112(cacheDir, cacheKey);
92785
92998
  if (existsSync72(cachePath2)) {
92786
92999
  return new Response(new Uint8Array(readFileSync102(cachePath2)), {
92787
- headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=60" }
93000
+ headers: { "Content-Type": contentType, "Cache-Control": "no-cache" }
92788
93001
  });
92789
93002
  }
92790
93003
  try {
@@ -92808,7 +93021,7 @@ function registerThumbnailRoutes(api, adapter2) {
92808
93021
  if (!existsSync72(cacheDir)) mkdirSync52(cacheDir, { recursive: true });
92809
93022
  writeFileSync62(cachePath2, buffer);
92810
93023
  return new Response(new Uint8Array(buffer), {
92811
- headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=60" }
93024
+ headers: { "Content-Type": contentType, "Cache-Control": "no-cache" }
92812
93025
  });
92813
93026
  } catch (err) {
92814
93027
  const msg = err instanceof Error ? err.message : String(err);
@@ -93172,6 +93385,8 @@ var init_dist9 = __esm({
93172
93385
  "add-keyframe",
93173
93386
  "update-keyframe",
93174
93387
  "remove-keyframe",
93388
+ "move-keyframe",
93389
+ "resize-keyframed-tween",
93175
93390
  "remove-all-keyframes",
93176
93391
  "add-with-keyframes",
93177
93392
  "replace-with-keyframes",
@@ -108475,12 +108690,12 @@ import { existsSync as existsSync54, lstatSync as lstatSync3, symlinkSync as sym
108475
108690
  import { resolve as resolve31, dirname as dirname24, basename as basename9, join as join61 } from "path";
108476
108691
  import { fileURLToPath as fileURLToPath8 } from "url";
108477
108692
  import { createRequire as createRequire2 } from "module";
108478
- function previewBaseUrl(port) {
108479
- return `http://127.0.0.1:${port}`;
108693
+ function previewBaseUrl(port, host = "127.0.0.1") {
108694
+ return `http://${host}:${port}`;
108480
108695
  }
108481
- function absolutePreviewUrl(port, path2) {
108696
+ function absolutePreviewUrl(port, path2, host = "127.0.0.1") {
108482
108697
  if (/^https?:\/\//.test(path2)) return path2;
108483
- return `${previewBaseUrl(port)}${path2.startsWith("/") ? path2 : `/${path2}`}`;
108698
+ return `${previewBaseUrl(port, host)}${path2.startsWith("/") ? path2 : `/${path2}`}`;
108484
108699
  }
108485
108700
  function hasExplicitPreviewPort(argv2) {
108486
108701
  return argv2.some((arg) => arg === "--port" || arg.startsWith("--port="));
@@ -108501,7 +108716,7 @@ function previewServerPayload(server) {
108501
108716
  port: server.port,
108502
108717
  projectName: server.projectName,
108503
108718
  projectDir: server.projectDir,
108504
- url: previewBaseUrl(server.port)
108719
+ url: previewBaseUrl(server.port, server.host)
108505
108720
  };
108506
108721
  }
108507
108722
  function parseContextFields(value) {
@@ -108578,7 +108793,7 @@ async function printCurrentSelection(projectDir, startPort, json, preferredPort)
108578
108793
  }
108579
108794
  const selection = {
108580
108795
  ...response.selection,
108581
- thumbnailUrl: absolutePreviewUrl(server.port, response.selection.thumbnailUrl)
108796
+ thumbnailUrl: absolutePreviewUrl(server.port, response.selection.thumbnailUrl, server.host)
108582
108797
  };
108583
108798
  if (json) {
108584
108799
  console.log(
@@ -108728,7 +108943,7 @@ async function printCurrentContext(projectDir, startPort, options) {
108728
108943
  console.log(`${c.success("\u25C7")} Studio context`);
108729
108944
  if (contextIncludes(fields, "server")) {
108730
108945
  console.log(` ${c.dim("Project")} ${server.projectName}`);
108731
- console.log(` ${c.dim("Studio")} ${previewBaseUrl(server.port)}`);
108946
+ console.log(` ${c.dim("Studio")} ${previewBaseUrl(server.port, server.host)}`);
108732
108947
  }
108733
108948
  if (contextIncludes(fields, "selection")) {
108734
108949
  if (selection.ok) {