svg-scroll-draw 2.23.4 → 2.23.5

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.
Files changed (101) hide show
  1. package/README.md +4 -4
  2. package/dist/angular/index.cjs +3 -3
  3. package/dist/angular/index.d.mts +3 -3
  4. package/dist/angular/index.d.ts +3 -3
  5. package/dist/angular/index.mjs +1 -1
  6. package/dist/astro/index.cjs +2 -2
  7. package/dist/astro/index.d.mts +3 -3
  8. package/dist/astro/index.d.ts +3 -3
  9. package/dist/astro/index.mjs +1 -1
  10. package/dist/cdn/svg-scroll-draw.dev.global.js +190 -265
  11. package/dist/cdn/svg-scroll-draw.global.js +3 -3
  12. package/dist/{chunk-DSFD227B.mjs → chunk-22B37AWY.mjs} +1 -1
  13. package/dist/{chunk-YNNA33A5.mjs → chunk-BSW7W2Y5.mjs} +1 -1
  14. package/dist/{chunk-XTPAW6XR.mjs → chunk-CZLUBJAI.mjs} +1 -1
  15. package/dist/chunk-K6VATIJH.mjs +3 -0
  16. package/dist/chunk-NV6YTPHI.mjs +1 -0
  17. package/dist/chunk-NYQJPPMP.mjs +1 -0
  18. package/dist/{chunk-ZNCZYV3Q.mjs → chunk-OSGWGHQJ.mjs} +1 -1
  19. package/dist/chunk-PAGN26EH.mjs +1 -0
  20. package/dist/chunk-THPTANES.mjs +1 -0
  21. package/dist/{chunk-OJFWQ6CU.mjs → chunk-V3Z6G5JE.mjs} +1 -1
  22. package/dist/chunk-VJ5ZU55P.mjs +1 -0
  23. package/dist/chunk-XNM3VKEK.mjs +1 -0
  24. package/dist/cinematic/index.cjs +2 -2
  25. package/dist/cinematic/index.mjs +1 -1
  26. package/dist/{engine-B7UpB4fT.d.ts → engine-6VsjEwzb.d.ts} +1 -1
  27. package/dist/{engine-o1VSQ1lX.d.mts → engine-BLWKCfxC.d.mts} +1 -1
  28. package/dist/group/index.cjs +3 -3
  29. package/dist/group/index.d.mts +3 -3
  30. package/dist/group/index.d.ts +3 -3
  31. package/dist/group/index.mjs +1 -1
  32. package/dist/horizontal/index.cjs +1 -1
  33. package/dist/horizontal/index.d.mts +1 -1
  34. package/dist/horizontal/index.d.ts +1 -1
  35. package/dist/horizontal/index.mjs +1 -1
  36. package/dist/{index-D3o4vT3e.d.ts → index-BN8yKeQ3.d.ts} +1 -1
  37. package/dist/{index-BY-CNE8c.d.mts → index-DAiRJgtF.d.mts} +2 -2
  38. package/dist/{index-CdaBYn3A.d.mts → index-DVjblK_4.d.mts} +1 -1
  39. package/dist/{index-DqXXiDIk.d.ts → index-hSQqLVbg.d.ts} +2 -2
  40. package/dist/index.cjs +4 -4
  41. package/dist/index.d.mts +6 -6
  42. package/dist/index.d.ts +6 -6
  43. package/dist/index.mjs +1 -1
  44. package/dist/nuxt/index.cjs +3 -3
  45. package/dist/nuxt/index.d.mts +3 -3
  46. package/dist/nuxt/index.d.ts +3 -3
  47. package/dist/nuxt/index.mjs +1 -1
  48. package/dist/progress/index.cjs +1 -1
  49. package/dist/progress/index.d.mts +1 -1
  50. package/dist/progress/index.d.ts +1 -1
  51. package/dist/progress/index.mjs +1 -1
  52. package/dist/react/index.cjs +2 -2
  53. package/dist/react/index.d.mts +3 -3
  54. package/dist/react/index.d.ts +3 -3
  55. package/dist/react/index.mjs +1 -1
  56. package/dist/reveal/index.cjs +1 -1
  57. package/dist/reveal/index.d.mts +1 -1
  58. package/dist/reveal/index.d.ts +1 -1
  59. package/dist/reveal/index.mjs +1 -1
  60. package/dist/{scroll-draw-DsBMkwrX.d.ts → scroll-draw-BsU_Ohmu.d.ts} +1 -1
  61. package/dist/{scroll-draw-Dej-GIRP.d.mts → scroll-draw-Fzir8hlU.d.mts} +1 -1
  62. package/dist/snap/index.cjs +1 -1
  63. package/dist/snap/index.d.mts +1 -1
  64. package/dist/snap/index.d.ts +1 -1
  65. package/dist/snap/index.mjs +1 -1
  66. package/dist/solid/index.cjs +3 -3
  67. package/dist/solid/index.d.mts +3 -3
  68. package/dist/solid/index.d.ts +3 -3
  69. package/dist/solid/index.mjs +1 -1
  70. package/dist/svelte/index.cjs +3 -3
  71. package/dist/svelte/index.d.mts +3 -3
  72. package/dist/svelte/index.d.ts +3 -3
  73. package/dist/svelte/index.mjs +1 -1
  74. package/dist/text/index.cjs +1 -1
  75. package/dist/text/index.d.mts +1 -1
  76. package/dist/text/index.d.ts +1 -1
  77. package/dist/text/index.mjs +1 -1
  78. package/dist/timeline/index.cjs +9 -9
  79. package/dist/timeline/index.d.mts +1 -1
  80. package/dist/timeline/index.d.ts +1 -1
  81. package/dist/timeline/index.mjs +8 -8
  82. package/dist/{types-MswK0erX.d.mts → types-9bcJdVcg.d.mts} +6 -2
  83. package/dist/{types-MswK0erX.d.ts → types-9bcJdVcg.d.ts} +6 -2
  84. package/dist/video/index.cjs +1 -1
  85. package/dist/video/index.d.mts +1 -1
  86. package/dist/video/index.d.ts +1 -1
  87. package/dist/video/index.mjs +1 -1
  88. package/dist/vue/index.cjs +3 -3
  89. package/dist/vue/index.d.mts +3 -3
  90. package/dist/vue/index.d.ts +3 -3
  91. package/dist/vue/index.mjs +1 -1
  92. package/dist/web-component/index.cjs +3 -3
  93. package/dist/web-component/index.mjs +1 -1
  94. package/package.json +1 -1
  95. package/dist/chunk-6TWFLRUB.mjs +0 -3
  96. package/dist/chunk-A4JCC3QQ.mjs +0 -1
  97. package/dist/chunk-DM6EDKWH.mjs +0 -1
  98. package/dist/chunk-I73SOXBN.mjs +0 -1
  99. package/dist/chunk-NLPSVYFP.mjs +0 -1
  100. package/dist/chunk-OPXWNJBG.mjs +0 -1
  101. package/dist/chunk-QFSTKVA3.mjs +0 -1
@@ -93,7 +93,8 @@ var SvgScrollDraw = (() => {
93
93
  "ease-in": (t) => t * t,
94
94
  "ease-out": (t) => t * (2 - t),
95
95
  "ease-in-out": (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
96
- spring: (t) => 1 - Math.cos(t * Math.PI * 2.5) * Math.pow(1 - t, 2.2),
96
+ // createSpring's defaults, the same arithmetic in the same order.
97
+ spring: createSpring(),
97
98
  bounce: createBounce(),
98
99
  elastic: createElastic()
99
100
  };
@@ -110,30 +111,12 @@ var SvgScrollDraw = (() => {
110
111
  const [element = "top", viewport = "bottom"] = trimmed.split(/\s+/).filter(Boolean);
111
112
  return { element, viewport };
112
113
  }
114
+ var anchorAt = (anchor, other) => anchor === "top" ? 0 : anchor === "center" ? 0.5 : anchor === "bottom" ? 1 : other;
113
115
  function elementAnchorY(top, height, scrollY, anchor) {
114
- switch (anchor) {
115
- case "top":
116
- return top + scrollY;
117
- case "center":
118
- return top + scrollY + height / 2;
119
- case "bottom":
120
- return top + scrollY + height;
121
- default:
122
- return top + scrollY;
123
- }
116
+ return top + scrollY + height * anchorAt(anchor, 0);
124
117
  }
125
118
  function viewportAnchorY(anchor, vpHeight) {
126
- if (/^\d+(\.\d+)?%$/.test(anchor)) return vpHeight * (parseFloat(anchor) / 100);
127
- switch (anchor) {
128
- case "top":
129
- return 0;
130
- case "center":
131
- return vpHeight / 2;
132
- case "bottom":
133
- return vpHeight;
134
- default:
135
- return vpHeight;
136
- }
119
+ return vpHeight * (/^\d+(\.\d+)?%$/.test(anchor) ? parseFloat(anchor) / 100 : anchorAt(anchor, 1));
137
120
  }
138
121
  function computeProgress(scrollY, tStart, tEnd, speed) {
139
122
  if (tEnd === tStart) return 0;
@@ -313,6 +296,45 @@ var SvgScrollDraw = (() => {
313
296
  registry().delete(el);
314
297
  }
315
298
 
299
+ // src/core/motion-watch.ts
300
+ function watchReducedMotion(cb) {
301
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
302
+ return () => {
303
+ };
304
+ }
305
+ const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
306
+ const handler = (e) => cb(!!e.matches);
307
+ if (typeof mq.addEventListener === "function") {
308
+ mq.addEventListener("change", handler);
309
+ return () => mq.removeEventListener("change", handler);
310
+ }
311
+ const legacy = mq;
312
+ legacy.addListener?.(handler);
313
+ return () => legacy.removeListener?.(handler);
314
+ }
315
+
316
+ // src/core/motion-live.ts
317
+ function finishWhenReduced(options, build) {
318
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return build(options, true);
319
+ let inst = build(options, false);
320
+ const unwatch = watchReducedMotion((reduced) => {
321
+ if (!reduced) return;
322
+ unwatch();
323
+ const finished = (inst.getProgress?.() ?? 0) >= 1;
324
+ inst.destroy();
325
+ inst = build(finished ? { ...options, onComplete: void 0 } : options, true);
326
+ });
327
+ const live = {};
328
+ for (const key of Object.keys(inst)) {
329
+ live[key] = (...args) => inst[key]?.(...args);
330
+ }
331
+ live.destroy = () => {
332
+ unwatch();
333
+ inst.destroy();
334
+ };
335
+ return live;
336
+ }
337
+
316
338
  // src/core/layout-watch.ts
317
339
  var observer;
318
340
  var watchers = /* @__PURE__ */ new Set();
@@ -366,43 +388,53 @@ var SvgScrollDraw = (() => {
366
388
  };
367
389
  }
368
390
 
369
- // src/core/motion-watch.ts
370
- function watchReducedMotion(cb) {
371
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
372
- return () => {
373
- };
374
- }
375
- const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
376
- const handler = (e) => cb(!!e.matches);
377
- if (typeof mq.addEventListener === "function") {
378
- mq.addEventListener("change", handler);
379
- return () => mq.removeEventListener("change", handler);
380
- }
381
- const legacy = mq;
382
- legacy.addListener?.(handler);
383
- return () => legacy.removeListener?.(handler);
384
- }
385
-
386
- // src/core/motion-live.ts
387
- function finishWhenReduced(options, build) {
388
- if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return build(options, true);
389
- let inst = build(options, false);
390
- const unwatch = watchReducedMotion((reduced) => {
391
- if (!reduced) return;
392
- unwatch();
393
- const finished = (inst.getProgress?.() ?? 0) >= 1;
394
- inst.destroy();
395
- inst = build(finished ? { ...options, onComplete: void 0 } : options, true);
396
- });
397
- const live = {};
398
- for (const key of Object.keys(inst)) {
399
- live[key] = (...args) => inst[key]?.(...args);
400
- }
401
- live.destroy = () => {
402
- unwatch();
403
- inst.destroy();
391
+ // src/core/frame-gate.ts
392
+ function frameGate(scroller, watched, at, frame, measure) {
393
+ let raf;
394
+ let painted = NaN;
395
+ let held;
396
+ let timer;
397
+ const tick = () => {
398
+ raf = 0;
399
+ frame();
400
+ if (!held && !raf && (painted = at()) > 0 && painted < 1) raf = requestAnimationFrame(tick);
401
+ };
402
+ const wake = () => {
403
+ if (!raf && !held && at() !== painted) raf = requestAnimationFrame(tick);
404
+ };
405
+ const hold = (on) => {
406
+ held = on;
407
+ cancelAnimationFrame(raf);
408
+ raf = painted = NaN;
409
+ wake();
410
+ };
411
+ const remeasure = () => {
412
+ clearTimeout(timer);
413
+ measure();
414
+ wake();
415
+ };
416
+ const later = () => {
417
+ clearTimeout(timer);
418
+ timer = setTimeout(remeasure, 150);
419
+ };
420
+ const unwatch = watchLayout(watched, later);
421
+ const listen = (method) => {
422
+ scroller[method]("scroll", wake, { passive: true });
423
+ window[method]("resize", later);
424
+ window[method]("orientationchange", later);
425
+ };
426
+ listen("addEventListener");
427
+ wake();
428
+ return {
429
+ hold,
430
+ remeasure,
431
+ off() {
432
+ hold(true);
433
+ listen("removeEventListener");
434
+ unwatch();
435
+ clearTimeout(timer);
436
+ }
404
437
  };
405
- return live;
406
438
  }
407
439
 
408
440
  // src/core/engine.ts
@@ -568,11 +600,11 @@ var SvgScrollDraw = (() => {
568
600
  let tStart = 0;
569
601
  let tEnd = 0;
570
602
  let staggerFit = stagger;
571
- let tLast = 0;
603
+ let gStart = 0;
604
+ let gEnd = 0;
572
605
  let completed = false;
573
606
  let started = false;
574
607
  let rafId = 0;
575
- let isVisible = false;
576
608
  let frozenAlpha = -1;
577
609
  let frozenPath = [];
578
610
  let prevScroll = -1;
@@ -580,6 +612,7 @@ var SvgScrollDraw = (() => {
580
612
  let currentAlpha = 0;
581
613
  let repeatCount = 0;
582
614
  let repeatTimer;
615
+ let parked = false;
583
616
  let debugOverlay = null;
584
617
  function destroyDebugOverlay() {
585
618
  debugOverlay?.destroy();
@@ -613,7 +646,10 @@ var SvgScrollDraw = (() => {
613
646
  const room = s[`scroll${d}`] - s[`client${d}`] - 1 - tStart - range / speed;
614
647
  if (room >= 0) staggerFit = Math.min(stagger, room / (gaps * range));
615
648
  }
616
- tLast = tEnd + gaps * staggerFit * range;
649
+ const span = Math.max(0, gaps) * staggerFit * range;
650
+ const len = range / Math.min(speed, 1);
651
+ gStart = tStart + Math.min(0, span, len, span + len);
652
+ gEnd = tStart + Math.max(0, span, len, span + len);
617
653
  }
618
654
  function cacheTriggers() {
619
655
  ({ tStart, tEnd } = measureTriggers());
@@ -941,7 +977,7 @@ var SvgScrollDraw = (() => {
941
977
  resetPaths();
942
978
  rafId = requestAnimationFrame(tick);
943
979
  }
944
- const observer3 = new IntersectionObserver(
980
+ const observer2 = new IntersectionObserver(
945
981
  (entries) => {
946
982
  entries.forEach((e) => {
947
983
  if (e.isIntersecting && !(once && completed)) {
@@ -955,23 +991,23 @@ var SvgScrollDraw = (() => {
955
991
  },
956
992
  { root: scrollEl ?? null, threshold, rootMargin }
957
993
  );
958
- let resizeTimer2;
959
- function onResize2() {
960
- clearTimeout(resizeTimer2);
961
- resizeTimer2 = setTimeout(() => paths.forEach(measure), 150);
994
+ let resizeTimer;
995
+ function onResize() {
996
+ clearTimeout(resizeTimer);
997
+ resizeTimer = setTimeout(() => paths.forEach(measure), 150);
962
998
  }
963
- window.addEventListener("resize", onResize2);
964
- window.addEventListener("orientationchange", onResize2);
965
- if (delay > 0) setTimeout(() => observer3.observe(container), delay);
966
- else observer3.observe(container);
999
+ window.addEventListener("resize", onResize);
1000
+ window.addEventListener("orientationchange", onResize);
1001
+ if (delay > 0) setTimeout(() => observer2.observe(container), delay);
1002
+ else observer2.observe(container);
967
1003
  return {
968
1004
  destroy() {
969
1005
  cancelAnimationFrame(rafId);
970
1006
  clearTimeout(repeatTimer);
971
- observer3.disconnect();
972
- window.removeEventListener("resize", onResize2);
973
- window.removeEventListener("orientationchange", onResize2);
974
- clearTimeout(resizeTimer2);
1007
+ observer2.disconnect();
1008
+ window.removeEventListener("resize", onResize);
1009
+ window.removeEventListener("orientationchange", onResize);
1010
+ clearTimeout(resizeTimer);
975
1011
  },
976
1012
  replay() {
977
1013
  repeatCount = 0;
@@ -1004,21 +1040,39 @@ var SvgScrollDraw = (() => {
1004
1040
  },
1005
1041
  /** No trigger window on this path — it runs on time — so lengths only. */
1006
1042
  refresh() {
1007
- clearTimeout(resizeTimer2);
1043
+ clearTimeout(resizeTimer);
1008
1044
  paths.forEach(measure);
1009
1045
  }
1010
1046
  };
1011
1047
  }
1012
1048
  if (autoplay) return tracked(buildAutoplay());
1013
1049
  cacheTriggers();
1050
+ const at = () => computeProgress(scrollPos(), gStart, gEnd, 1);
1051
+ function complete() {
1052
+ completed = true;
1053
+ onComplete?.();
1054
+ if (repeatCount < (repeat === "infinite" ? Infinity : repeat)) {
1055
+ repeatCount++;
1056
+ repeatTimer = setTimeout(() => {
1057
+ parked = true;
1058
+ }, repeatDelay);
1059
+ }
1060
+ }
1061
+ function restart() {
1062
+ frozenAlpha = -1;
1063
+ frozenPath = [];
1064
+ started = false;
1065
+ completed = false;
1066
+ parked = false;
1067
+ firedWaypoints.clear();
1068
+ resetPaths();
1069
+ dirty = true;
1070
+ }
1014
1071
  function update() {
1015
- if (paused || !looping) return;
1016
1072
  const now = performance.now();
1017
1073
  const currentScroll = scrollPos();
1018
- if (!dirty && velocityScale === false && currentScroll === lastAppliedScroll) {
1019
- next(currentScroll);
1020
- return;
1021
- }
1074
+ if (parked && at() % 1) restart();
1075
+ if (!dirty && velocityScale === false && currentScroll === lastAppliedScroll) return;
1022
1076
  dirty = false;
1023
1077
  lastAppliedScroll = currentScroll;
1024
1078
  let effectiveSpeed = speed;
@@ -1037,9 +1091,9 @@ var SvgScrollDraw = (() => {
1037
1091
  const rawProgress = range === 0 ? 0 : (currentScroll - tStart) / range;
1038
1092
  if (!isNaN(prevRawProgress)) {
1039
1093
  if (prevRawProgress <= 0 && rawProgress > 0) onEnter?.();
1040
- else if (prevRawProgress > 0 && rawProgress <= 0) onLeaveBack?.();
1041
1094
  if (prevRawProgress < 1 && rawProgress >= 1) onLeave?.();
1042
- else if (prevRawProgress >= 1 && rawProgress < 1) onEnterBack?.();
1095
+ if (prevRawProgress >= 1 && rawProgress < 1) onEnterBack?.();
1096
+ if (prevRawProgress > 0 && rawProgress <= 0) onLeaveBack?.();
1043
1097
  }
1044
1098
  prevRawProgress = rawProgress;
1045
1099
  if (clipDirection) {
@@ -1054,23 +1108,10 @@ var SvgScrollDraw = (() => {
1054
1108
  onStart?.();
1055
1109
  }
1056
1110
  if (alpha >= 1 && !completed) {
1057
- completed = true;
1058
- onComplete?.();
1059
- const maxRepeats = repeat === "infinite" ? Infinity : repeat ?? 0;
1060
- if (repeatCount < maxRepeats) {
1061
- repeatCount++;
1062
- repeatTimer = setTimeout(() => {
1063
- frozenAlpha = -1;
1064
- frozenPath = [];
1065
- started = false;
1066
- completed = false;
1067
- resetPaths();
1068
- }, repeatDelay);
1069
- }
1111
+ complete();
1070
1112
  } else if (alpha < 1 && !once) {
1071
1113
  completed = false;
1072
1114
  }
1073
- next(currentScroll);
1074
1115
  return;
1075
1116
  }
1076
1117
  paths.forEach((el, i) => {
@@ -1099,114 +1140,60 @@ var SvgScrollDraw = (() => {
1099
1140
  onStart?.();
1100
1141
  }
1101
1142
  if (allComplete && !completed) {
1102
- completed = true;
1103
- onComplete?.();
1104
- const maxRepeats = repeat === "infinite" ? Infinity : repeat ?? 0;
1105
- if (repeatCount < maxRepeats) {
1106
- repeatCount++;
1107
- repeatTimer = setTimeout(() => {
1108
- frozenAlpha = -1;
1109
- frozenPath = [];
1110
- started = false;
1111
- completed = false;
1112
- firedWaypoints.clear();
1113
- resetPaths();
1114
- dirty = true;
1115
- }, repeatDelay);
1116
- }
1143
+ complete();
1117
1144
  } else if (!allComplete && !once) {
1118
1145
  completed = false;
1119
1146
  }
1120
- next(currentScroll);
1121
- }
1122
- function inStaggerTail(scroll) {
1123
- return scroll >= tEnd && scroll < tLast;
1124
1147
  }
1125
- function next(scroll) {
1126
- if (isVisible || inStaggerTail(scroll)) rafId = requestAnimationFrame(update);
1127
- else looping = false;
1128
- }
1129
- function live() {
1130
- return isVisible || inStaggerTail(scrollPos());
1131
- }
1132
- let looping = false;
1133
- function startLoop() {
1134
- if (looping) return;
1135
- looping = true;
1136
- rafId = requestAnimationFrame(function frame() {
1137
- update();
1138
- });
1139
- }
1140
- function stopLoop() {
1141
- looping = false;
1142
- cancelAnimationFrame(rafId);
1143
- }
1144
- const observer2 = new IntersectionObserver(
1145
- (entries) => {
1146
- entries.forEach((e) => {
1147
- isVisible = e.isIntersecting;
1148
- if (isVisible && !paused) {
1149
- dirty = true;
1150
- startLoop();
1151
- } else if (!(looping && !paused && inStaggerTail(scrollPos()))) {
1152
- stopLoop();
1153
- }
1154
- });
1155
- },
1156
- { root: scrollEl ?? null, threshold, rootMargin }
1148
+ const gate = frameGate(
1149
+ scrollEl ?? window,
1150
+ [container],
1151
+ at,
1152
+ update,
1153
+ () => {
1154
+ const before = lengths.join();
1155
+ paths.forEach(measure);
1156
+ cacheTriggers();
1157
+ dirty = true;
1158
+ if (lengths.join() !== before) go();
1159
+ }
1157
1160
  );
1158
- function remeasure() {
1159
- paths.forEach(measure);
1160
- cacheTriggers();
1161
- dirty = true;
1162
- }
1163
- let resizeTimer;
1164
- function onResize() {
1165
- clearTimeout(resizeTimer);
1166
- resizeTimer = setTimeout(remeasure, 150);
1167
- }
1168
- window.addEventListener("resize", onResize);
1169
- window.addEventListener("orientationchange", onResize);
1170
- const unwatch = watchLayout([container], onResize);
1171
- if (delay > 0) setTimeout(() => observer2.observe(container), delay);
1172
- else observer2.observe(container);
1161
+ let waiting = delay > 0;
1162
+ function go() {
1163
+ gate.hold(paused || waiting);
1164
+ }
1165
+ let delayTimer;
1166
+ if (waiting) delayTimer = setTimeout(() => {
1167
+ waiting = false;
1168
+ go();
1169
+ }, delay);
1170
+ go();
1173
1171
  return tracked({
1174
1172
  destroy() {
1175
- cancelAnimationFrame(rafId);
1176
1173
  clearTimeout(repeatTimer);
1177
- stopLoop();
1178
- observer2.disconnect();
1179
- unwatch();
1180
- window.removeEventListener("resize", onResize);
1181
- window.removeEventListener("orientationchange", onResize);
1182
- clearTimeout(resizeTimer);
1174
+ clearTimeout(delayTimer);
1175
+ gate.off();
1183
1176
  destroyDebugOverlay();
1184
1177
  },
1185
1178
  replay() {
1186
- frozenAlpha = -1;
1187
- frozenPath = [];
1179
+ restart();
1188
1180
  prevScroll = -1;
1189
1181
  prevVelScroll = -1;
1190
- started = false;
1191
- completed = false;
1192
1182
  repeatCount = 0;
1193
1183
  paused = false;
1194
1184
  currentAlpha = 0;
1195
- firedWaypoints.clear();
1196
1185
  clearTimeout(repeatTimer);
1197
- resetPaths();
1198
- dirty = true;
1199
- if (live()) startLoop();
1186
+ go();
1200
1187
  },
1201
1188
  pause() {
1202
1189
  paused = true;
1203
- stopLoop();
1190
+ gate.hold(true);
1204
1191
  },
1205
1192
  resume() {
1206
1193
  if (!paused) return;
1207
1194
  paused = false;
1208
1195
  dirty = true;
1209
- if (live()) startLoop();
1196
+ go();
1210
1197
  },
1211
1198
  seek(progress) {
1212
1199
  const p = Math.min(1, Math.max(0, progress));
@@ -1214,7 +1201,7 @@ var SvgScrollDraw = (() => {
1214
1201
  frozenAlpha = p;
1215
1202
  frozenPath = [];
1216
1203
  paused = true;
1217
- stopLoop();
1204
+ gate.hold(true);
1218
1205
  applyAlpha(p, direction);
1219
1206
  dirty = true;
1220
1207
  },
@@ -1228,11 +1215,7 @@ var SvgScrollDraw = (() => {
1228
1215
  * window — run immediately and marked dirty so the next frame repaints from
1229
1216
  * the new numbers.
1230
1217
  */
1231
- refresh() {
1232
- clearTimeout(resizeTimer);
1233
- remeasure();
1234
- if (live() && !paused) startLoop();
1235
- }
1218
+ refresh: gate.remeasure
1236
1219
  }, () => ({ tStart, tEnd }));
1237
1220
  }
1238
1221
 
@@ -1483,8 +1466,6 @@ var SvgScrollDraw = (() => {
1483
1466
  if (nativeEligible()) return buildNative();
1484
1467
  let tStart = 0;
1485
1468
  let tEnd = 0;
1486
- let rafId = 0;
1487
- let painted = NaN;
1488
1469
  let paused = false;
1489
1470
  let frozenAlpha = -1;
1490
1471
  let frozenRaw = 0;
@@ -1526,15 +1507,11 @@ var SvgScrollDraw = (() => {
1526
1507
  return;
1527
1508
  }
1528
1509
  if (prevRawProgress <= 0 && raw > 0) onEnter?.();
1529
- else if (prevRawProgress > 0 && raw <= 0) onLeaveBack?.();
1530
1510
  if (prevRawProgress < 1 && raw >= 1) onLeave?.();
1531
- else if (prevRawProgress >= 1 && raw < 1) onEnterBack?.();
1511
+ if (prevRawProgress >= 1 && raw < 1) onEnterBack?.();
1512
+ if (prevRawProgress > 0 && raw <= 0) onLeaveBack?.();
1532
1513
  prevRawProgress = raw;
1533
1514
  }
1534
- const gate = (scroll) => computeProgress(scroll, tStart, tEnd, Math.min(speed, 1));
1535
- function wake() {
1536
- if (!rafId && !paused && gate(scrollPos()) !== painted) rafId = requestAnimationFrame(update);
1537
- }
1538
1515
  function update() {
1539
1516
  if (paused) return;
1540
1517
  const now = performance.now();
@@ -1560,10 +1537,14 @@ var SvgScrollDraw = (() => {
1560
1537
  } else if (alpha < 1 && !once) {
1561
1538
  completed = false;
1562
1539
  }
1563
- if (paused) return;
1564
- painted = gate(currentScroll);
1565
- rafId = painted > 0 && painted < 1 ? requestAnimationFrame(update) : 0;
1566
1540
  }
1541
+ const gate = frameGate(
1542
+ scrollEl ?? window,
1543
+ [triggerEl],
1544
+ () => computeProgress(scrollPos(), tStart, tEnd, Math.min(speed, 1)),
1545
+ update,
1546
+ cacheTriggers
1547
+ );
1567
1548
  cacheTriggers();
1568
1549
  if (tEnd === tStart) {
1569
1550
  warn("scrollAnimate: zero-length trigger window, so it never animates. In a sticky stage, set triggerElement.", el);
@@ -1573,21 +1554,6 @@ var SvgScrollDraw = (() => {
1573
1554
  currentAlpha = easeFn(frozenRaw);
1574
1555
  applyAlpha(currentAlpha);
1575
1556
  }
1576
- function remeasure() {
1577
- cacheTriggers();
1578
- wake();
1579
- }
1580
- let resizeTimer;
1581
- function onResize() {
1582
- clearTimeout(resizeTimer);
1583
- resizeTimer = setTimeout(remeasure, 150);
1584
- }
1585
- const scroller = scrollEl ?? window;
1586
- scroller.addEventListener("scroll", wake, { passive: true });
1587
- window.addEventListener("resize", onResize);
1588
- window.addEventListener("orientationchange", onResize);
1589
- const unwatch = watchLayout([triggerEl], onResize);
1590
- wake();
1591
1557
  _register(el, {
1592
1558
  type: "animate",
1593
1559
  getProgress: () => currentAlpha,
@@ -1595,18 +1561,12 @@ var SvgScrollDraw = (() => {
1595
1561
  });
1596
1562
  function halt() {
1597
1563
  paused = true;
1598
- cancelAnimationFrame(rafId);
1599
- rafId = 0;
1600
- painted = NaN;
1564
+ gate.hold(true);
1601
1565
  }
1602
1566
  return {
1603
1567
  destroy() {
1604
- halt();
1605
- scroller.removeEventListener("scroll", wake);
1606
- window.removeEventListener("resize", onResize);
1607
- window.removeEventListener("orientationchange", onResize);
1608
- unwatch();
1609
- clearTimeout(resizeTimer);
1568
+ paused = true;
1569
+ gate.off();
1610
1570
  restoreInline();
1611
1571
  _unregister(el);
1612
1572
  },
@@ -1617,14 +1577,13 @@ var SvgScrollDraw = (() => {
1617
1577
  currentAlpha = 0;
1618
1578
  paused = false;
1619
1579
  applyAlpha(0);
1620
- painted = 0;
1621
- wake();
1580
+ gate.hold(false);
1622
1581
  },
1623
1582
  pause: halt,
1624
1583
  resume() {
1625
1584
  if (!paused) return;
1626
1585
  paused = false;
1627
- wake();
1586
+ gate.hold(false);
1628
1587
  },
1629
1588
  seek(p) {
1630
1589
  const clamped = Math.min(1, Math.max(0, p));
@@ -1637,7 +1596,7 @@ var SvgScrollDraw = (() => {
1637
1596
  getProgress() {
1638
1597
  return currentAlpha;
1639
1598
  },
1640
- refresh: remeasure
1599
+ refresh: gate.remeasure
1641
1600
  };
1642
1601
  }
1643
1602
 
@@ -1737,9 +1696,6 @@ var SvgScrollDraw = (() => {
1737
1696
  let tStart = 0;
1738
1697
  let tEnd = 0;
1739
1698
  let measured = false;
1740
- let rafId = 0;
1741
- let isVisible = false;
1742
- let paused = false;
1743
1699
  let frozenAlpha = -1;
1744
1700
  let frozenRaw = 0;
1745
1701
  let currentAlpha = 0;
@@ -1765,9 +1721,9 @@ var SvgScrollDraw = (() => {
1765
1721
  el.textContent = fmt(from + (to - from) * alpha);
1766
1722
  el.style.setProperty("--scroll-draw-progress", String(alpha));
1767
1723
  }
1724
+ const at = () => computeProgress(scrollPos(), tStart, tEnd, 1);
1768
1725
  function update() {
1769
- if (!isVisible || paused) return;
1770
- const progress = computeProgress(scrollPos(), tStart, tEnd, 1);
1726
+ const progress = at();
1771
1727
  const alpha = once ? Math.max(frozenAlpha, easeFn(frozenRaw = Math.max(frozenRaw, progress))) : easeFn(progress);
1772
1728
  currentAlpha = alpha;
1773
1729
  applyAlpha(alpha);
@@ -1777,7 +1733,6 @@ var SvgScrollDraw = (() => {
1777
1733
  } else if (alpha < 1 && !once) {
1778
1734
  completed = false;
1779
1735
  }
1780
- rafId = requestAnimationFrame(update);
1781
1736
  }
1782
1737
  cacheTriggers();
1783
1738
  {
@@ -1786,42 +1741,16 @@ var SvgScrollDraw = (() => {
1786
1741
  currentAlpha = initAlpha;
1787
1742
  applyAlpha(initAlpha);
1788
1743
  }
1789
- const observer2 = new IntersectionObserver(
1790
- (entries) => {
1791
- entries.forEach((e) => {
1792
- isVisible = e.isIntersecting;
1793
- if (isVisible && !paused) rafId = requestAnimationFrame(update);
1794
- else cancelAnimationFrame(rafId);
1795
- });
1796
- }
1797
- );
1798
- let resizeTimer;
1799
- function onResize() {
1800
- clearTimeout(resizeTimer);
1801
- resizeTimer = setTimeout(cacheTriggers, 150);
1802
- }
1803
- window.addEventListener("resize", onResize);
1804
- window.addEventListener("orientationchange", onResize);
1805
- const unwatch = watchLayout([el], onResize);
1806
- observer2.observe(el);
1744
+ const gate = frameGate(window, [el], at, update, cacheTriggers);
1807
1745
  _register(el, {
1808
1746
  type: "counter",
1809
1747
  getProgress: () => currentAlpha,
1810
1748
  getTrigger: () => ({ tStart, tEnd })
1811
1749
  });
1812
- function resume() {
1813
- if (!paused) return;
1814
- paused = false;
1815
- if (isVisible) rafId = requestAnimationFrame(update);
1816
- }
1750
+ const resume = () => gate.hold(false);
1817
1751
  return {
1818
1752
  destroy() {
1819
- cancelAnimationFrame(rafId);
1820
- observer2.disconnect();
1821
- window.removeEventListener("resize", onResize);
1822
- window.removeEventListener("orientationchange", onResize);
1823
- unwatch();
1824
- clearTimeout(resizeTimer);
1753
+ gate.off();
1825
1754
  el.style.setProperty("--scroll-draw-progress", savedVar);
1826
1755
  _unregister(el);
1827
1756
  },
@@ -1833,18 +1762,14 @@ var SvgScrollDraw = (() => {
1833
1762
  applyAlpha(0);
1834
1763
  resume();
1835
1764
  },
1836
- pause() {
1837
- paused = true;
1838
- cancelAnimationFrame(rafId);
1839
- },
1765
+ pause: () => gate.hold(true),
1840
1766
  resume,
1841
1767
  seek(p) {
1842
1768
  const clamped = Math.min(1, Math.max(0, p));
1843
1769
  currentAlpha = clamped;
1844
1770
  frozenAlpha = clamped;
1845
1771
  frozenRaw = 0;
1846
- paused = true;
1847
- cancelAnimationFrame(rafId);
1772
+ gate.hold(true);
1848
1773
  applyAlpha(clamped);
1849
1774
  },
1850
1775
  getProgress() {