@cosmictraveler002/anim-kit 1.0.0
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/LICENSE +21 -0
- package/README.md +1033 -0
- package/dist/anim-kit.standalone.js +117 -0
- package/dist/anim-kit.standalone.js.map +1 -0
- package/dist/core/gsap.d.ts +44 -0
- package/dist/core/gsap.d.ts.map +1 -0
- package/dist/core/gsap.js +71 -0
- package/dist/core/gsap.js.map +1 -0
- package/dist/core/guard.d.ts +3 -0
- package/dist/core/guard.d.ts.map +1 -0
- package/dist/core/guard.js +18 -0
- package/dist/core/guard.js.map +1 -0
- package/dist/core/smooth-scroll.d.ts +45 -0
- package/dist/core/smooth-scroll.d.ts.map +1 -0
- package/dist/core/smooth-scroll.js +98 -0
- package/dist/core/smooth-scroll.js.map +1 -0
- package/dist/core/split.d.ts +24 -0
- package/dist/core/split.d.ts.map +1 -0
- package/dist/core/split.js +117 -0
- package/dist/core/split.js.map +1 -0
- package/dist/core/types.d.ts +21 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +9 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/util.d.ts +19 -0
- package/dist/core/util.d.ts.map +1 -0
- package/dist/core/util.js +73 -0
- package/dist/core/util.js.map +1 -0
- package/dist/effects/counter.d.ts +52 -0
- package/dist/effects/counter.d.ts.map +1 -0
- package/dist/effects/counter.js +106 -0
- package/dist/effects/counter.js.map +1 -0
- package/dist/effects/cursor-follower.d.ts +19 -0
- package/dist/effects/cursor-follower.d.ts.map +1 -0
- package/dist/effects/cursor-follower.js +76 -0
- package/dist/effects/cursor-follower.js.map +1 -0
- package/dist/effects/drag-strip.d.ts +17 -0
- package/dist/effects/drag-strip.d.ts.map +1 -0
- package/dist/effects/drag-strip.js +186 -0
- package/dist/effects/drag-strip.js.map +1 -0
- package/dist/effects/hero-shrink.d.ts +15 -0
- package/dist/effects/hero-shrink.d.ts.map +1 -0
- package/dist/effects/hero-shrink.js +40 -0
- package/dist/effects/hero-shrink.js.map +1 -0
- package/dist/effects/horizontal-scroll.d.ts +17 -0
- package/dist/effects/horizontal-scroll.d.ts.map +1 -0
- package/dist/effects/horizontal-scroll.js +87 -0
- package/dist/effects/horizontal-scroll.js.map +1 -0
- package/dist/effects/line-reveal.d.ts +34 -0
- package/dist/effects/line-reveal.d.ts.map +1 -0
- package/dist/effects/line-reveal.js +71 -0
- package/dist/effects/line-reveal.js.map +1 -0
- package/dist/effects/liquid-button.d.ts +19 -0
- package/dist/effects/liquid-button.d.ts.map +1 -0
- package/dist/effects/liquid-button.js +52 -0
- package/dist/effects/liquid-button.js.map +1 -0
- package/dist/effects/logo-reveal.d.ts +15 -0
- package/dist/effects/logo-reveal.d.ts.map +1 -0
- package/dist/effects/logo-reveal.js +49 -0
- package/dist/effects/logo-reveal.js.map +1 -0
- package/dist/effects/marquee.d.ts +13 -0
- package/dist/effects/marquee.d.ts.map +1 -0
- package/dist/effects/marquee.js +143 -0
- package/dist/effects/marquee.js.map +1 -0
- package/dist/effects/mask-reveal.d.ts +36 -0
- package/dist/effects/mask-reveal.d.ts.map +1 -0
- package/dist/effects/mask-reveal.js +102 -0
- package/dist/effects/mask-reveal.js.map +1 -0
- package/dist/effects/menu-overlay.d.ts +32 -0
- package/dist/effects/menu-overlay.d.ts.map +1 -0
- package/dist/effects/menu-overlay.js +150 -0
- package/dist/effects/menu-overlay.js.map +1 -0
- package/dist/effects/nav-hide.d.ts +13 -0
- package/dist/effects/nav-hide.d.ts.map +1 -0
- package/dist/effects/nav-hide.js +68 -0
- package/dist/effects/nav-hide.js.map +1 -0
- package/dist/effects/parallax.d.ts +11 -0
- package/dist/effects/parallax.d.ts.map +1 -0
- package/dist/effects/parallax.js +48 -0
- package/dist/effects/parallax.js.map +1 -0
- package/dist/effects/preloader.d.ts +33 -0
- package/dist/effects/preloader.d.ts.map +1 -0
- package/dist/effects/preloader.js +128 -0
- package/dist/effects/preloader.js.map +1 -0
- package/dist/effects/scatter-text.d.ts +20 -0
- package/dist/effects/scatter-text.d.ts.map +1 -0
- package/dist/effects/scatter-text.js +87 -0
- package/dist/effects/scatter-text.js.map +1 -0
- package/dist/effects/stacked-cards.d.ts +24 -0
- package/dist/effects/stacked-cards.d.ts.map +1 -0
- package/dist/effects/stacked-cards.js +106 -0
- package/dist/effects/stacked-cards.js.map +1 -0
- package/dist/effects/theme-reveal.d.ts +35 -0
- package/dist/effects/theme-reveal.d.ts.map +1 -0
- package/dist/effects/theme-reveal.js +93 -0
- package/dist/effects/theme-reveal.js.map +1 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/styles/anim-kit.css +361 -0
- package/package.json +80 -0
- package/src/core/gsap.ts +79 -0
- package/src/core/guard.ts +18 -0
- package/src/core/smooth-scroll.ts +143 -0
- package/src/core/split.ts +145 -0
- package/src/core/types.ts +30 -0
- package/src/core/util.ts +79 -0
- package/src/effects/counter.ts +192 -0
- package/src/effects/cursor-follower.ts +104 -0
- package/src/effects/drag-strip.ts +228 -0
- package/src/effects/hero-shrink.ts +69 -0
- package/src/effects/horizontal-scroll.ts +123 -0
- package/src/effects/line-reveal.ts +109 -0
- package/src/effects/liquid-button.ts +75 -0
- package/src/effects/logo-reveal.ts +76 -0
- package/src/effects/marquee.ts +157 -0
- package/src/effects/mask-reveal.ts +148 -0
- package/src/effects/menu-overlay.ts +218 -0
- package/src/effects/nav-hide.ts +90 -0
- package/src/effects/parallax.ts +68 -0
- package/src/effects/preloader.ts +187 -0
- package/src/effects/scatter-text.ts +129 -0
- package/src/effects/stacked-cards.ts +154 -0
- package/src/effects/theme-reveal.ts +144 -0
- package/src/index.ts +98 -0
- package/src/styles/anim-kit.css +361 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { CommonOptions, Destroy, TargetLike } from "../core/types.js";
|
|
2
|
+
export interface CounterOptions extends CommonOptions {
|
|
3
|
+
/** Start value. @default 0 */
|
|
4
|
+
from?: number;
|
|
5
|
+
/** End value. @default 100 */
|
|
6
|
+
to?: number;
|
|
7
|
+
/** Duration in seconds. @default 4 */
|
|
8
|
+
duration?: number;
|
|
9
|
+
/** GSAP ease. @default "power1.inOut" */
|
|
10
|
+
ease?: string;
|
|
11
|
+
/** Pad with leading zeros to this width. @default 0 (no padding) */
|
|
12
|
+
pad?: number;
|
|
13
|
+
/** Suffix appended to the number, e.g. "+". @default "" */
|
|
14
|
+
suffix?: string;
|
|
15
|
+
/** Animate when scrolled into view instead of immediately. @default false */
|
|
16
|
+
onScroll?: boolean;
|
|
17
|
+
start?: string;
|
|
18
|
+
onComplete?: (value: number) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare function counter(target: TargetLike, options?: CounterOptions): Destroy;
|
|
21
|
+
/**
|
|
22
|
+
* Audio bars — the 5-bar equaliser inside the background-music button.
|
|
23
|
+
*
|
|
24
|
+
* Heights re-randomise on an interval and each bar springs to its new height,
|
|
25
|
+
* giving that loose, twitchy look. `stop()` collapses the bars back down.
|
|
26
|
+
*
|
|
27
|
+
* const eq = audioBars(".ak-eq");
|
|
28
|
+
* eq.start(); // on play
|
|
29
|
+
* eq.stop(); // on pause
|
|
30
|
+
*/
|
|
31
|
+
export interface AudioBarsOptions extends CommonOptions {
|
|
32
|
+
/** Bars inside the container. @default ":scope > *" */
|
|
33
|
+
bar?: string;
|
|
34
|
+
/** Re-randomise interval in ms. @default 100 */
|
|
35
|
+
interval?: number;
|
|
36
|
+
/** Min bar height px. @default 4 */
|
|
37
|
+
minHeight?: number;
|
|
38
|
+
/** Max bar height px. @default 14 */
|
|
39
|
+
maxHeight?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Spring feel, 0..1. Higher = bouncier. Used to pick the overshoot ease.
|
|
42
|
+
* @default 0.75
|
|
43
|
+
*/
|
|
44
|
+
bounce?: number;
|
|
45
|
+
}
|
|
46
|
+
export interface AudioBarsHandle {
|
|
47
|
+
start: () => void;
|
|
48
|
+
stop: () => void;
|
|
49
|
+
destroy: Destroy;
|
|
50
|
+
}
|
|
51
|
+
export declare function audioBars(target: TargetLike, options?: AudioBarsOptions): AudioBarsHandle;
|
|
52
|
+
//# sourceMappingURL=counter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../../src/effects/counter.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3E,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CA0DjF;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,SAAS,CACvB,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CA+DjB"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counter — the big tabular-nums number that ticks up.
|
|
3
|
+
*
|
|
4
|
+
* Drives an element's `textContent` from `from` to `to` with an easing curve,
|
|
5
|
+
* optionally triggered by ScrollTrigger. Uses integer stepping so there is no
|
|
6
|
+
* fractional flicker, and pairs with `tabular-nums` for stable layout.
|
|
7
|
+
*
|
|
8
|
+
* counter("[data-count]", { to: 100, duration: 4, ease: "power1.inOut" })
|
|
9
|
+
*/
|
|
10
|
+
import { gsap, ScrollTrigger, initGSAP, killTweens } from "../core/gsap.js";
|
|
11
|
+
import { guard } from "../core/guard.js";
|
|
12
|
+
import { toArray } from "../core/util.js";
|
|
13
|
+
export function counter(target, options = {}) {
|
|
14
|
+
initGSAP();
|
|
15
|
+
const els = toArray(target);
|
|
16
|
+
if (!els.length)
|
|
17
|
+
return () => { };
|
|
18
|
+
const { from = 0, to = 100, duration = 4, ease = "power1.inOut", pad = 0, suffix = "", onScroll = false, start = "top 90%", onComplete, } = options;
|
|
19
|
+
return guard(options, run);
|
|
20
|
+
function run() {
|
|
21
|
+
const tweens = [];
|
|
22
|
+
els.forEach((el) => {
|
|
23
|
+
const state = { v: from };
|
|
24
|
+
const render = () => {
|
|
25
|
+
const n = Math.round(state.v);
|
|
26
|
+
el.textContent = (pad ? String(n).padStart(pad, "0") : String(n)) + suffix;
|
|
27
|
+
};
|
|
28
|
+
render();
|
|
29
|
+
const vars = {
|
|
30
|
+
v: to,
|
|
31
|
+
duration,
|
|
32
|
+
ease,
|
|
33
|
+
onUpdate: render,
|
|
34
|
+
onComplete: () => {
|
|
35
|
+
render();
|
|
36
|
+
onComplete?.(Math.round(state.v));
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
if (onScroll) {
|
|
40
|
+
vars.scrollTrigger = { trigger: el, start, once: true };
|
|
41
|
+
}
|
|
42
|
+
tweens.push(gsap.to(state, vars));
|
|
43
|
+
});
|
|
44
|
+
if (onScroll)
|
|
45
|
+
ScrollTrigger.refresh();
|
|
46
|
+
return () => {
|
|
47
|
+
tweens.forEach((t) => {
|
|
48
|
+
t.scrollTrigger?.kill();
|
|
49
|
+
t.kill();
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function audioBars(target, options = {}) {
|
|
55
|
+
initGSAP();
|
|
56
|
+
const inert = { start: () => { }, stop: () => { }, destroy: () => { } };
|
|
57
|
+
const root = toArray(target)[0];
|
|
58
|
+
if (!root)
|
|
59
|
+
return inert;
|
|
60
|
+
const { bar = ":scope > *", interval = 100, minHeight = 4, maxHeight = 14, bounce = 0.75, } = options;
|
|
61
|
+
const bars = toArray(bar, root);
|
|
62
|
+
if (!bars.length)
|
|
63
|
+
return inert;
|
|
64
|
+
let timer = 0;
|
|
65
|
+
const start = () => {
|
|
66
|
+
if (timer)
|
|
67
|
+
return;
|
|
68
|
+
randomise();
|
|
69
|
+
timer = window.setInterval(randomise, interval);
|
|
70
|
+
};
|
|
71
|
+
const stop = () => {
|
|
72
|
+
if (timer)
|
|
73
|
+
window.clearInterval(timer);
|
|
74
|
+
timer = 0;
|
|
75
|
+
bars.forEach((b) => gsap.to(b, { height: minHeight, duration: 0.4, ease: "power2.out", overwrite: "auto" }));
|
|
76
|
+
};
|
|
77
|
+
const destroy = guard(options, () => {
|
|
78
|
+
gsap.set(bars, { height: minHeight, force3D: true });
|
|
79
|
+
start();
|
|
80
|
+
return () => {
|
|
81
|
+
if (timer)
|
|
82
|
+
window.clearInterval(timer); // match window.setInterval in start()
|
|
83
|
+
timer = 0;
|
|
84
|
+
// Kill in-flight bar tweens first — otherwise their next frame would
|
|
85
|
+
// rewrite `height` *after* clearProps, mutating the DOM post-destroy.
|
|
86
|
+
// killTweens() (not killTweensOf) also catches batches created since
|
|
87
|
+
// the last ticker frame — those are still lazy and survive killTweensOf.
|
|
88
|
+
killTweens(bars);
|
|
89
|
+
gsap.set(bars, { clearProps: "height" });
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
return { start, stop, destroy };
|
|
93
|
+
function randomise() {
|
|
94
|
+
bars.forEach((b) => {
|
|
95
|
+
const v = Math.random() * 0.8 + 0.2;
|
|
96
|
+
gsap.to(b, {
|
|
97
|
+
height: Math.max(minHeight, maxHeight * v),
|
|
98
|
+
duration: 0.45,
|
|
99
|
+
// Underdamped springs overshoot; map the bounce option onto back.out.
|
|
100
|
+
ease: `back.out(${(bounce * 1.8).toFixed(2)})`,
|
|
101
|
+
overwrite: "auto",
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=counter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter.js","sourceRoot":"","sources":["../../src/effects/counter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CommonOptions, Destroy, TargetLike } from "../core/types.js";
|
|
2
|
+
export interface CursorFollowerOptions extends CommonOptions {
|
|
3
|
+
/** The floating element. Defaults to the first `[data-cursor]` in the document. */
|
|
4
|
+
follower?: TargetLike;
|
|
5
|
+
/** Offset added to the pointer position, px. @default 14 */
|
|
6
|
+
offset?: number;
|
|
7
|
+
/** Spring config for the follower. @default { mass: 0.1, stiffness: 120 } */
|
|
8
|
+
spring?: {
|
|
9
|
+
mass?: number;
|
|
10
|
+
stiffness?: number;
|
|
11
|
+
damping?: number;
|
|
12
|
+
};
|
|
13
|
+
/** Blend mode applied to the follower. @default "exclusion" */
|
|
14
|
+
blendMode?: string;
|
|
15
|
+
/** Fade the follower in/out with the pointer. @default true */
|
|
16
|
+
fade?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function cursorFollower(zone: TargetLike, options?: CursorFollowerOptions): Destroy;
|
|
19
|
+
//# sourceMappingURL=cursor-follower.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-follower.d.ts","sourceRoot":"","sources":["../../src/effects/cursor-follower.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3E,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,mFAAmF;IACnF,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAyET"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor follower — the "Play Showreel" tag that trails the pointer.
|
|
3
|
+
*
|
|
4
|
+
* Two springs drive X and Y independently (mass 0.1, as on the site), and the
|
|
5
|
+
* whole thing fades/blurs in when the pointer enters the hot zone. The label
|
|
6
|
+
* uses `mix-blend-mode: exclusion` so it inverts over any background.
|
|
7
|
+
*
|
|
8
|
+
* cursorFollower(zone, { follower: ".ak-cursor" })
|
|
9
|
+
*/
|
|
10
|
+
import { gsap, initGSAP, killTweens } from "../core/gsap.js";
|
|
11
|
+
import { guard } from "../core/guard.js";
|
|
12
|
+
import { one } from "../core/util.js";
|
|
13
|
+
export function cursorFollower(zone, options = {}) {
|
|
14
|
+
initGSAP();
|
|
15
|
+
const el = (options.follower ? one(options.follower) : null) ??
|
|
16
|
+
document.querySelector("[data-cursor]");
|
|
17
|
+
const area = one(zone);
|
|
18
|
+
if (!el || !area)
|
|
19
|
+
return () => { };
|
|
20
|
+
const { offset = 14, spring = { mass: 0.1, stiffness: 120 }, blendMode = "exclusion", fade = true } = options;
|
|
21
|
+
return guard(options, () => {
|
|
22
|
+
const prevStyle = {
|
|
23
|
+
mixBlendMode: el.style.mixBlendMode,
|
|
24
|
+
position: el.style.position,
|
|
25
|
+
left: el.style.left,
|
|
26
|
+
top: el.style.top,
|
|
27
|
+
pointerEvents: el.style.pointerEvents,
|
|
28
|
+
};
|
|
29
|
+
el.style.mixBlendMode = blendMode;
|
|
30
|
+
el.style.position = "absolute";
|
|
31
|
+
el.style.left = "0";
|
|
32
|
+
el.style.top = "0";
|
|
33
|
+
el.style.pointerEvents = "none";
|
|
34
|
+
gsap.set(el, { opacity: fade ? 0 : 1, x: 0, y: 0 });
|
|
35
|
+
const xTo = gsap.quickTo(el, "x", { ...spring, duration: 0.4, ease: "power3" });
|
|
36
|
+
const yTo = gsap.quickTo(el, "y", { ...spring, duration: 0.4, ease: "power3" });
|
|
37
|
+
const onMove = (e) => {
|
|
38
|
+
const r = area.getBoundingClientRect();
|
|
39
|
+
xTo(e.clientX - r.left + offset);
|
|
40
|
+
yTo(e.clientY - r.top + offset);
|
|
41
|
+
if (fade)
|
|
42
|
+
gsap.to(el, { opacity: 1, duration: 0.25, overwrite: "auto" });
|
|
43
|
+
};
|
|
44
|
+
const onLeave = () => {
|
|
45
|
+
if (fade)
|
|
46
|
+
gsap.to(el, { opacity: 0, duration: 0.25, overwrite: "auto" });
|
|
47
|
+
};
|
|
48
|
+
const onKey = (e) => {
|
|
49
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
50
|
+
/* host app handles activation; keep zone keyboard-reachable */
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
area.addEventListener("pointermove", onMove);
|
|
54
|
+
area.addEventListener("pointerleave", onLeave);
|
|
55
|
+
area.addEventListener("keydown", onKey);
|
|
56
|
+
return () => {
|
|
57
|
+
area.removeEventListener("pointermove", onMove);
|
|
58
|
+
area.removeEventListener("pointerleave", onLeave);
|
|
59
|
+
area.removeEventListener("keydown", onKey);
|
|
60
|
+
// quickTo tweens are paused at creation and would otherwise sit on the
|
|
61
|
+
// global timeline forever; fade tweens may still be in flight.
|
|
62
|
+
xTo.tween.kill();
|
|
63
|
+
yTo.tween.kill();
|
|
64
|
+
killTweens(el);
|
|
65
|
+
// Restore the inline styles we overwrote, clear only what gsap set
|
|
66
|
+
// (the old clearProps:"all" also wiped the consumer's own styles).
|
|
67
|
+
el.style.mixBlendMode = prevStyle.mixBlendMode;
|
|
68
|
+
el.style.position = prevStyle.position;
|
|
69
|
+
el.style.left = prevStyle.left;
|
|
70
|
+
el.style.top = prevStyle.top;
|
|
71
|
+
el.style.pointerEvents = prevStyle.pointerEvents;
|
|
72
|
+
gsap.set(el, { clearProps: "opacity,transform" });
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=cursor-follower.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-follower.js","sourceRoot":"","sources":["../../src/effects/cursor-follower.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CommonOptions, Destroy, TargetLike } from "../core/types.js";
|
|
2
|
+
export interface DragStripOptions extends CommonOptions {
|
|
3
|
+
/** Max rotation at full drag speed, degrees. @default 100 */
|
|
4
|
+
maxRotation?: number;
|
|
5
|
+
/** Rotation response — divisor on the normalised drag speed. @default 100 */
|
|
6
|
+
rotationScale?: number;
|
|
7
|
+
/** Spring-back duration on release, seconds. @default 1 */
|
|
8
|
+
settleDuration?: number;
|
|
9
|
+
/** Enable inertia after release (requires GSAP InertiaPlugin). @default false */
|
|
10
|
+
inertia?: boolean;
|
|
11
|
+
/** Duplicate content so the loop is seamless; `false` clamps instead. @default true */
|
|
12
|
+
clone?: boolean;
|
|
13
|
+
/** Items inside the strip that rotate. @default ":scope > *" */
|
|
14
|
+
item?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function dragStrip(target: TargetLike, options?: DragStripOptions): Destroy;
|
|
17
|
+
//# sourceMappingURL=drag-strip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drag-strip.d.ts","sourceRoot":"","sources":["../../src/effects/drag-strip.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3E,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uFAAuF;IACvF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAiLrF"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drag strip — the grabbable, infinitely looping image carousel.
|
|
3
|
+
*
|
|
4
|
+
* Built on GSAP Draggable. Why it is shaped this way (audit notes):
|
|
5
|
+
*
|
|
6
|
+
* - **Single writer.** Draggable owns the track's X transform; the loop is a
|
|
7
|
+
* `liveSnap` function Draggable itself calls on every move (and every frame
|
|
8
|
+
* of an inertia throw). Nothing else writes X — the first version let a
|
|
9
|
+
* 0.5s `quickTo` fight Draggable's own transform, which stuttered between
|
|
10
|
+
* wrapped and unwrapped positions. (Note: Draggable has no `modifiers`
|
|
11
|
+
* option; `liveSnap` is the supported hook.)
|
|
12
|
+
* - **Seamless loop.** Folding positions is only invisible when the content
|
|
13
|
+
* tiles: with `clone: true` (default) the strip duplicates itself until one
|
|
14
|
+
* tile is at least as wide as the viewport, and the fold distance is always
|
|
15
|
+
* a whole multiple of the tile width — the same trick `marquee()` uses.
|
|
16
|
+
* Without cloning there is nothing to fold against, so the strip clamps at
|
|
17
|
+
* the content edges instead (finite, but never a gap).
|
|
18
|
+
* - **Rotation on pull.** Children tilt against pointer *speed* (normalised to
|
|
19
|
+
* a 60fps frame so mouse and touch event rates feel identical) and spring
|
|
20
|
+
* back to 0 on release. Pointer movement is used rather than Draggable's
|
|
21
|
+
* `deltaX`, because deltaX jumps by a full loop at the seam.
|
|
22
|
+
* - **Fidelity.** `destroy()` kills the Draggable and both rotation tweens,
|
|
23
|
+
* removes cloned tiles (original markup back) and restores the inline
|
|
24
|
+
* cursor/user-select/touch-action the effect had overwritten.
|
|
25
|
+
*
|
|
26
|
+
* dragStrip(".ak-drag-track", { maxRotation: 60 })
|
|
27
|
+
*
|
|
28
|
+
* CSS: viewport `overflow: hidden`; track `display: flex; width: max-content;
|
|
29
|
+
* gap: 1rem; cursor: grab; user-select: none; touch-action: pan-y`.
|
|
30
|
+
*/
|
|
31
|
+
import { gsap, Draggable, initGSAP } from "../core/gsap.js";
|
|
32
|
+
import { guard } from "../core/guard.js";
|
|
33
|
+
import { one, toArray } from "../core/util.js";
|
|
34
|
+
export function dragStrip(target, options = {}) {
|
|
35
|
+
initGSAP();
|
|
36
|
+
const track = one(target);
|
|
37
|
+
if (!track)
|
|
38
|
+
return () => { };
|
|
39
|
+
const { maxRotation = 100, rotationScale = 100, settleDuration = 1, inertia = false, clone = true, item = ":scope > *", } = options;
|
|
40
|
+
return guard(options, () => {
|
|
41
|
+
const viewport = track.parentElement;
|
|
42
|
+
const prevStyle = {
|
|
43
|
+
cursor: track.style.cursor,
|
|
44
|
+
userSelect: track.style.userSelect,
|
|
45
|
+
touchAction: track.style.touchAction,
|
|
46
|
+
};
|
|
47
|
+
/* ---------------- tiling (seamless infinite) ---------------- */
|
|
48
|
+
const originalCount = track.children.length;
|
|
49
|
+
const originalNodes = Array.from(track.children);
|
|
50
|
+
const trackWidth = () => Math.max(track.scrollWidth, track.clientWidth);
|
|
51
|
+
let tile = originalCount > 0 ? trackWidth() : 0; // width of one copy
|
|
52
|
+
let viewportW = 1; // width of the scroll viewport (the parent)
|
|
53
|
+
let loop = 0; // fold distance — whole tiles, or 0 when nothing to fold
|
|
54
|
+
let pointerDown = false;
|
|
55
|
+
let throwing = false;
|
|
56
|
+
/** Clone a tile, stripping ids so duplicated markup stays valid. */
|
|
57
|
+
const cloneTile = () => originalNodes.map((node) => {
|
|
58
|
+
const copy = node.cloneNode(true);
|
|
59
|
+
if (copy instanceof Element) {
|
|
60
|
+
if (copy.id)
|
|
61
|
+
copy.removeAttribute("id");
|
|
62
|
+
copy.querySelectorAll("[id]").forEach((el) => el.removeAttribute("id"));
|
|
63
|
+
}
|
|
64
|
+
return copy;
|
|
65
|
+
});
|
|
66
|
+
const measure = () => {
|
|
67
|
+
viewportW = Math.max(1, viewport?.clientWidth || track.clientWidth || 1);
|
|
68
|
+
if (tile > 0 && clone) {
|
|
69
|
+
// One tile must be ≥ the viewport, with a spare tile to fold into.
|
|
70
|
+
for (let i = 8; i > 0 && trackWidth() - tile < viewportW; i--) {
|
|
71
|
+
track.append(...cloneTile());
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (tile <= 0) {
|
|
75
|
+
loop = 0; // unmeasurable (hidden / jsdom) — drag without folding
|
|
76
|
+
}
|
|
77
|
+
else if (clone) {
|
|
78
|
+
// Largest multiple of `tile` that still leaves room for the viewport.
|
|
79
|
+
loop = Math.max(0, Math.floor((trackWidth() - viewportW) / tile)) * tile;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Finite mode: keep the content aligned, never an empty gap.
|
|
83
|
+
loop = Math.max(0, trackWidth() - viewportW);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const fold = (value) => {
|
|
87
|
+
if (loop <= 0)
|
|
88
|
+
return value;
|
|
89
|
+
return clone
|
|
90
|
+
? gsap.utils.wrap(-loop, 0, value)
|
|
91
|
+
: Math.max(-loop, Math.min(0, value));
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Handed to Draggable as `liveSnap.x`. Folds while Draggable is driving
|
|
95
|
+
* the value (pointer down, or a throw in progress). InertiaPlugin parses
|
|
96
|
+
* its *end target* with both flags false — that value stays raw so the
|
|
97
|
+
* throw keeps its direction; syncXY folds every frame of the throw instead.
|
|
98
|
+
*/
|
|
99
|
+
const foldWhenDriven = (value) => pointerDown || throwing ? fold(value) : value;
|
|
100
|
+
measure();
|
|
101
|
+
/* ---------------- rotation on pull ---------------- */
|
|
102
|
+
const items = toArray(item, track); // after cloning: tiles tilt too
|
|
103
|
+
gsap.set(items, { transformOrigin: "50% 100%" });
|
|
104
|
+
const followRotation = gsap.quickTo(items, "rotation", {
|
|
105
|
+
duration: 0.12,
|
|
106
|
+
ease: "power2.out",
|
|
107
|
+
});
|
|
108
|
+
const settleRotation = gsap.quickTo(items, "rotation", {
|
|
109
|
+
duration: settleDuration,
|
|
110
|
+
ease: "power3.out",
|
|
111
|
+
});
|
|
112
|
+
let lastPointerX = 0;
|
|
113
|
+
let lastMoveTime = 0;
|
|
114
|
+
/* ---------------- drag ---------------- */
|
|
115
|
+
track.style.cursor = "grab";
|
|
116
|
+
track.style.userSelect = "none";
|
|
117
|
+
track.style.touchAction = "pan-y";
|
|
118
|
+
const draggable = Draggable.create(track, {
|
|
119
|
+
type: "x",
|
|
120
|
+
dragClickables: true,
|
|
121
|
+
inertia,
|
|
122
|
+
liveSnap: { x: foldWhenDriven },
|
|
123
|
+
onPress() {
|
|
124
|
+
pointerDown = true;
|
|
125
|
+
throwing = false;
|
|
126
|
+
// A spring from the previous release has had its chance — start fresh.
|
|
127
|
+
if (settleRotation.tween.isActive())
|
|
128
|
+
settleRotation.tween.totalProgress(1);
|
|
129
|
+
lastPointerX = this.pointerX || 0;
|
|
130
|
+
lastMoveTime = performance.now();
|
|
131
|
+
track.style.cursor = "grabbing";
|
|
132
|
+
},
|
|
133
|
+
onDrag() {
|
|
134
|
+
const now = performance.now();
|
|
135
|
+
const dt = Math.min(64, Math.max(8, now - lastMoveTime));
|
|
136
|
+
const pointerX = this.pointerX || 0;
|
|
137
|
+
const dx = pointerX - lastPointerX;
|
|
138
|
+
lastPointerX = pointerX;
|
|
139
|
+
lastMoveTime = now;
|
|
140
|
+
// Pointer speed normalised to a 60fps frame → same feel for every
|
|
141
|
+
// event rate (mouse vs touch), unlike a raw per-event delta.
|
|
142
|
+
const speed = (dx / dt) * 16.667;
|
|
143
|
+
const rotation = gsap.utils.clamp(-maxRotation, maxRotation, -(speed / rotationScale) * 100);
|
|
144
|
+
followRotation(rotation);
|
|
145
|
+
},
|
|
146
|
+
onRelease() {
|
|
147
|
+
pointerDown = false;
|
|
148
|
+
track.style.cursor = prevStyle.cursor || "grab";
|
|
149
|
+
// Hold the last tilt, then spring it back over settleDuration.
|
|
150
|
+
if (followRotation.tween.isActive())
|
|
151
|
+
followRotation.tween.totalProgress(1);
|
|
152
|
+
settleRotation(0);
|
|
153
|
+
},
|
|
154
|
+
onThrowUpdate: () => {
|
|
155
|
+
throwing = true; // from here on, liveSnap folds each frame
|
|
156
|
+
},
|
|
157
|
+
onThrowComplete: () => {
|
|
158
|
+
throwing = false;
|
|
159
|
+
},
|
|
160
|
+
// (throw interruption resets `throwing` on the next press)
|
|
161
|
+
})[0];
|
|
162
|
+
/* ---------------- resize ---------------- */
|
|
163
|
+
const onResize = () => {
|
|
164
|
+
const x = parseFloat(String(gsap.getProperty(track, "x") ?? 0)) || 0;
|
|
165
|
+
measure(); // widen if the viewport grew; never removes tiles
|
|
166
|
+
gsap.set(track, { x: fold(x) }); // re-fold into the new range
|
|
167
|
+
};
|
|
168
|
+
window.addEventListener("resize", onResize);
|
|
169
|
+
return () => {
|
|
170
|
+
window.removeEventListener("resize", onResize);
|
|
171
|
+
followRotation.tween.kill();
|
|
172
|
+
settleRotation.tween.kill();
|
|
173
|
+
draggable.kill();
|
|
174
|
+
// Restore the exact inline styles we overwrote (not clearProps:"all",
|
|
175
|
+
// which would also wipe the consumer's own inline styles).
|
|
176
|
+
track.style.cursor = prevStyle.cursor;
|
|
177
|
+
track.style.userSelect = prevStyle.userSelect;
|
|
178
|
+
track.style.touchAction = prevStyle.touchAction;
|
|
179
|
+
// Original markup back: drop cloned tiles, then clear our transforms.
|
|
180
|
+
while (track.children.length > originalCount)
|
|
181
|
+
track.removeChild(track.lastElementChild);
|
|
182
|
+
gsap.set([track, ...track.children], { clearProps: "transform,transformOrigin" });
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=drag-strip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drag-strip.js","sourceRoot":"","sources":["../../src/effects/drag-strip.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CommonOptions, Destroy, TargetLike } from "../core/types.js";
|
|
2
|
+
export interface HeroShrinkOptions extends CommonOptions {
|
|
3
|
+
/** How far down the element drifts, as a CSS length. @default "49vh" */
|
|
4
|
+
offsetY?: string;
|
|
5
|
+
/** Final scale. @default 0.23 */
|
|
6
|
+
scale?: number;
|
|
7
|
+
/** Scrub smoothing — higher = laggier. @default 1 */
|
|
8
|
+
scrub?: number;
|
|
9
|
+
start?: string;
|
|
10
|
+
end?: string;
|
|
11
|
+
/** Shift on X at the end. @default 0 */
|
|
12
|
+
offsetX?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function heroShrink(target: TargetLike, options?: HeroShrinkOptions): Destroy;
|
|
15
|
+
//# sourceMappingURL=hero-shrink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hero-shrink.d.ts","sourceRoot":"","sources":["../../src/effects/hero-shrink.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3E,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAsCvF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hero shrink — the showreel video that scales down as you scroll away.
|
|
3
|
+
*
|
|
4
|
+
* fromTo(el, { scale: 1, x: 0, y: 0 },
|
|
5
|
+
* { x: 0, y: "49vh", scale: 0.23, force3D: true,
|
|
6
|
+
* scrollTrigger: { trigger: el, start: "top top",
|
|
7
|
+
* end: "bottom top", scrub: 1 } })
|
|
8
|
+
*
|
|
9
|
+
* The video stays full-bleed at the top of the page and shrinks toward the
|
|
10
|
+
* bottom-centre as the section scrolls past, with `scrub: 1` giving it that
|
|
11
|
+
* heavy, lagging feel.
|
|
12
|
+
*/
|
|
13
|
+
import { gsap, ScrollTrigger, initGSAP } from "../core/gsap.js";
|
|
14
|
+
import { guard } from "../core/guard.js";
|
|
15
|
+
import { one } from "../core/util.js";
|
|
16
|
+
export function heroShrink(target, options = {}) {
|
|
17
|
+
initGSAP();
|
|
18
|
+
const el = one(target);
|
|
19
|
+
if (!el)
|
|
20
|
+
return () => { };
|
|
21
|
+
const { offsetY = "49vh", offsetX = "0px", scale = 0.23, scrub = 1, start = "top top", end = "bottom top", } = options;
|
|
22
|
+
return guard(options, () => {
|
|
23
|
+
const tween = gsap.fromTo(el, { scale: 1, x: 0, y: 0 }, {
|
|
24
|
+
x: offsetX,
|
|
25
|
+
y: offsetY,
|
|
26
|
+
scale,
|
|
27
|
+
force3D: true,
|
|
28
|
+
ease: "none",
|
|
29
|
+
scrollTrigger: { trigger: el, start, end, scrub },
|
|
30
|
+
});
|
|
31
|
+
ScrollTrigger.refresh();
|
|
32
|
+
return () => {
|
|
33
|
+
tween.scrollTrigger?.kill();
|
|
34
|
+
tween.kill();
|
|
35
|
+
gsap.set(el, { clearProps: "transform" });
|
|
36
|
+
ScrollTrigger.refresh();
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=hero-shrink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hero-shrink.js","sourceRoot":"","sources":["../../src/effects/hero-shrink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAgBtC,MAAM,UAAU,UAAU,CAAC,MAAkB,EAAE,UAA6B,EAAE;IAC5E,QAAQ,EAAE,CAAC;IAEX,MAAM,EAAE,GAAG,GAAG,CAAc,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC,EAAE;QAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IAEzB,MAAM,EACJ,OAAO,GAAG,MAAM,EAChB,OAAO,GAAG,KAAK,EACf,KAAK,GAAG,IAAI,EACZ,KAAK,GAAG,CAAC,EACT,KAAK,GAAG,SAAS,EACjB,GAAG,GAAG,YAAY,GACnB,GAAG,OAAO,CAAC;IAEZ,OAAO,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CACvB,EAAE,EACF,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EACxB;YACE,CAAC,EAAE,OAAO;YACV,CAAC,EAAE,OAAO;YACV,KAAK;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,MAAM;YACZ,aAAa,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE;SAClD,CACF,CAAC;QAEF,aAAa,CAAC,OAAO,EAAE,CAAC;QAExB,OAAO,GAAG,EAAE;YACV,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;YAC1C,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CommonOptions, Destroy, TargetLike } from "../core/types.js";
|
|
2
|
+
export interface HorizontalScrollOptions extends CommonOptions {
|
|
3
|
+
/** Pinned section (trigger). Defaults to the first argument's parent. */
|
|
4
|
+
section?: TargetLike;
|
|
5
|
+
/** Selector for images inside panels that get extra parallax. */
|
|
6
|
+
panelImage?: string | null;
|
|
7
|
+
/** Scrub smoothing for the horizontal movement. @default 0.5 */
|
|
8
|
+
scrub?: number;
|
|
9
|
+
/** Scrub smoothing for the image parallax. @default 0.2 */
|
|
10
|
+
imageScrub?: number;
|
|
11
|
+
/** Final X for the track; defaults to `track.scrollWidth - innerWidth`. */
|
|
12
|
+
travel?: () => number;
|
|
13
|
+
/** Kill ScrollTriggers created for the images. @default true */
|
|
14
|
+
imageParallax?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function horizontalScroll(target: TargetLike, options?: HorizontalScrollOptions): Destroy;
|
|
17
|
+
//# sourceMappingURL=horizontal-scroll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"horizontal-scroll.d.ts","sourceRoot":"","sources":["../../src/effects/horizontal-scroll.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3E,MAAM,WAAW,uBAAwB,SAAQ,aAAa;IAC5D,yEAAyE;IACzE,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAqFT"}
|