@vysmo/scroll 0.1.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 +110 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/observer.d.ts +36 -0
- package/dist/observer.d.ts.map +1 -0
- package/dist/observer.js +82 -0
- package/dist/observer.js.map +1 -0
- package/dist/progress.d.ts +14 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +36 -0
- package/dist/progress.js.map +1 -0
- package/dist/scroll-effect.d.ts +37 -0
- package/dist/scroll-effect.d.ts.map +1 -0
- package/dist/scroll-effect.js +39 -0
- package/dist/scroll-effect.js.map +1 -0
- package/dist/scroll-transition.d.ts +38 -0
- package/dist/scroll-transition.d.ts.map +1 -0
- package/dist/scroll-transition.js +42 -0
- package/dist/scroll-transition.js.map +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/zones.d.ts +56 -0
- package/dist/zones.d.ts.map +1 -0
- package/dist/zones.js +94 -0
- package/dist/zones.js.map +1 -0
- package/package.json +52 -0
- package/src/__tests__/__screenshots__/progress.test.ts/createScrollProgress-reaches-1-after-fully-scrolling-past-the-element-1.png +0 -0
- package/src/__tests__/observer.test.ts +60 -0
- package/src/__tests__/progress.test.ts +126 -0
- package/src/__tests__/scroll-effect.test.ts +135 -0
- package/src/__tests__/scroll-transition.test.ts +167 -0
- package/src/__tests__/ssr.test.ts +37 -0
- package/src/__tests__/types-check.ts +86 -0
- package/src/__tests__/zones.test.ts +175 -0
- package/src/index.ts +9 -0
- package/src/observer.ts +89 -0
- package/src/progress.ts +39 -0
- package/src/scroll-effect.ts +72 -0
- package/src/scroll-transition.ts +80 -0
- package/src/types.ts +19 -0
- package/src/zones.ts +103 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maesto LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @vysmo/scroll
|
|
2
|
+
|
|
3
|
+
Three primitives that bind scroll progress to the rest of the ecosystem: `createScrollProgress` (raw 0–1 emitter), `createScrollTransition` (drives any `@vysmo/transitions` render), `createScrollEffect` (drives any `@vysmo/effects` params). One shared rAF-throttled observer underneath. Headless — you own the canvas.
|
|
4
|
+
|
|
5
|
+
[Live demos](https://vysmo.com/scroll) · [Source](https://github.com/vysmodev)
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @vysmo/scroll
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For `createScrollTransition` / `createScrollEffect` you also need the corresponding consumer package:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @vysmo/transitions # for createScrollTransition
|
|
17
|
+
pnpm add @vysmo/effects # for createScrollEffect
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
### Raw scroll progress
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { createScrollProgress } from "@vysmo/scroll";
|
|
26
|
+
|
|
27
|
+
const handle = createScrollProgress({
|
|
28
|
+
element: document.querySelector(".hero")!,
|
|
29
|
+
onProgress: (p) => console.log(p), // 0..1 as the element sweeps the viewport
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// later
|
|
33
|
+
handle.destroy();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`progress` runs from `0` (element's top edge at the viewport's bottom) to `1` (element's bottom edge at the viewport's top). Pass `ease: (t) => …` to remap — anything from `@vysmo/easings` works.
|
|
37
|
+
|
|
38
|
+
### Drive a transition with scroll
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { Runner, crossZoom } from "@vysmo/transitions";
|
|
42
|
+
import { createScrollTransition } from "@vysmo/scroll";
|
|
43
|
+
|
|
44
|
+
const canvas = document.querySelector("canvas")!;
|
|
45
|
+
const runner = new Runner({ canvas });
|
|
46
|
+
|
|
47
|
+
createScrollTransition({
|
|
48
|
+
section: document.querySelector(".scroll-section")!,
|
|
49
|
+
runner,
|
|
50
|
+
transition: crossZoom,
|
|
51
|
+
from: imageA,
|
|
52
|
+
to: imageB,
|
|
53
|
+
});
|
|
54
|
+
// renders crossZoom on every scroll tick, automatically passing progress
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Drive an effect with scroll
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { Runner, blur } from "@vysmo/effects";
|
|
61
|
+
import { createScrollEffect } from "@vysmo/scroll";
|
|
62
|
+
|
|
63
|
+
const runner = new Runner({ canvas });
|
|
64
|
+
|
|
65
|
+
createScrollEffect({
|
|
66
|
+
section: document.querySelector(".hero")!,
|
|
67
|
+
runner,
|
|
68
|
+
effect: blur,
|
|
69
|
+
source: image,
|
|
70
|
+
paramsAt: (progress) => ({ radius: progress * 20 }), // unblur as user scrolls down
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Zone helpers
|
|
75
|
+
|
|
76
|
+
Most scroll-driven UIs don't want a single linear 0..1 — they want phases (intro → hold → outro). The `zones.ts` helpers compose:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { scrollPlateau, scrollRange, scrollZones, smoothstep } from "@vysmo/scroll";
|
|
80
|
+
|
|
81
|
+
scrollRange(0.2, 0.8); // remap [0.2, 0.8] → [0, 1]; clamp outside
|
|
82
|
+
scrollPlateau(0.4, 0.6); // 0..1 with a flat 1.0 plateau between [0.4, 0.6]
|
|
83
|
+
scrollZones(0.2, 0.8); // inverse of plateau — peaks at the edges, 0 in the middle
|
|
84
|
+
smoothstep; // t² (3 - 2t) — common easing for scroll
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
All return plain `(progress: number) => number` functions — pipe through `createScrollProgress`'s `ease` option, or use directly.
|
|
88
|
+
|
|
89
|
+
## Shared observer
|
|
90
|
+
|
|
91
|
+
Every primitive registers with one rAF-throttled `IntersectionObserver` + `scroll` listener — N elements cost one rAF tick per frame, not N. Access directly if you need it:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { sharedScrollObserver } from "@vysmo/scroll";
|
|
95
|
+
|
|
96
|
+
const obs = sharedScrollObserver();
|
|
97
|
+
obs.subscribe(element, { onScroll: (rect, vp) => /* ... */ });
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Characteristics
|
|
101
|
+
|
|
102
|
+
- **DOM-only.** Browser scrolling is the substrate; no Node fallback (the SSR test asserts the module loads, not that it functions without DOM).
|
|
103
|
+
- **Tiny.** ~2 KB gzipped for the full bundle; ~1 KB for `createScrollProgress` alone.
|
|
104
|
+
- **Tree-shakable.** `createScrollTransition` and `createScrollEffect` only pull in their respective peer libraries' types.
|
|
105
|
+
- **One rAF.** Observer is shared across all primitives.
|
|
106
|
+
- **SSR-safe at module load.** Guarded `typeof window` checks; observer is lazy-instantiated.
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { createScrollProgress } from "./progress.js";
|
|
2
|
+
export { createScrollTransition } from "./scroll-transition.js";
|
|
3
|
+
export type { ScrollTransitionOptions } from "./scroll-transition.js";
|
|
4
|
+
export { createScrollEffect } from "./scroll-effect.js";
|
|
5
|
+
export type { ScrollEffectOptions } from "./scroll-effect.js";
|
|
6
|
+
export { sharedScrollObserver, ScrollObserver } from "./observer.js";
|
|
7
|
+
export type { ScrollSubscriber } from "./observer.js";
|
|
8
|
+
export { scrollPlateau, scrollRange, scrollZones, smoothstep } from "./zones.js";
|
|
9
|
+
export type { EaseFn, Handle, ScrollProgressOptions } from "./types.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACrE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACjF,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createScrollProgress } from "./progress.js";
|
|
2
|
+
export { createScrollTransition } from "./scroll-transition.js";
|
|
3
|
+
export { createScrollEffect } from "./scroll-effect.js";
|
|
4
|
+
export { sharedScrollObserver, ScrollObserver } from "./observer.js";
|
|
5
|
+
export { scrollPlateau, scrollRange, scrollZones, smoothstep } from "./zones.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared rAF-throttled scroll / resize observer. Every primitive in this
|
|
3
|
+
* package (progress, parallax, sticky-pin, horizontal-section) registers
|
|
4
|
+
* its element here; the observer keeps one passive `scroll` listener on
|
|
5
|
+
* `window` for the lifetime of any subscription and tears it down once
|
|
6
|
+
* the last subscriber unsubscribes.
|
|
7
|
+
*
|
|
8
|
+
* Safe to import at module load: no window access happens until
|
|
9
|
+
* `subscribe()` is called.
|
|
10
|
+
*/
|
|
11
|
+
export interface ScrollSubscriber {
|
|
12
|
+
onScroll(rect: DOMRect, viewport: {
|
|
13
|
+
readonly width: number;
|
|
14
|
+
readonly height: number;
|
|
15
|
+
}): void;
|
|
16
|
+
}
|
|
17
|
+
export declare class ScrollObserver {
|
|
18
|
+
private subs;
|
|
19
|
+
private listening;
|
|
20
|
+
private rafId;
|
|
21
|
+
private readonly scheduler;
|
|
22
|
+
constructor();
|
|
23
|
+
subscribe(element: HTMLElement, subscriber: ScrollSubscriber): () => void;
|
|
24
|
+
private start;
|
|
25
|
+
private stop;
|
|
26
|
+
private scheduleUpdate;
|
|
27
|
+
/**
|
|
28
|
+
* Run every subscriber's callback with the current viewport + element
|
|
29
|
+
* rect. Exposed for tests that need deterministic flushes without
|
|
30
|
+
* waiting on rAF.
|
|
31
|
+
*/
|
|
32
|
+
flush(): void;
|
|
33
|
+
}
|
|
34
|
+
/** Lazy singleton — first call creates the observer. SSR-safe. */
|
|
35
|
+
export declare function sharedScrollObserver(): ScrollObserver;
|
|
36
|
+
//# sourceMappingURL=observer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer.d.ts","sourceRoot":"","sources":["../src/observer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CACN,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAC5D,IAAI,CAAC;CACT;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,IAAI,CAA4C;IACxD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;;IAMvC,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,GAAG,MAAM,IAAI;IAUzE,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,cAAc;IAStB;;;;OAIG;IACH,KAAK,IAAI,IAAI;CAUd;AAID,kEAAkE;AAClE,wBAAgB,oBAAoB,IAAI,cAAc,CAGrD"}
|
package/dist/observer.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared rAF-throttled scroll / resize observer. Every primitive in this
|
|
3
|
+
* package (progress, parallax, sticky-pin, horizontal-section) registers
|
|
4
|
+
* its element here; the observer keeps one passive `scroll` listener on
|
|
5
|
+
* `window` for the lifetime of any subscription and tears it down once
|
|
6
|
+
* the last subscriber unsubscribes.
|
|
7
|
+
*
|
|
8
|
+
* Safe to import at module load: no window access happens until
|
|
9
|
+
* `subscribe()` is called.
|
|
10
|
+
*/
|
|
11
|
+
export class ScrollObserver {
|
|
12
|
+
subs = new Map();
|
|
13
|
+
listening = false;
|
|
14
|
+
rafId = null;
|
|
15
|
+
scheduler;
|
|
16
|
+
constructor() {
|
|
17
|
+
this.scheduler = () => this.scheduleUpdate();
|
|
18
|
+
}
|
|
19
|
+
subscribe(element, subscriber) {
|
|
20
|
+
this.subs.set(element, subscriber);
|
|
21
|
+
if (!this.listening)
|
|
22
|
+
this.start();
|
|
23
|
+
this.scheduleUpdate();
|
|
24
|
+
return () => {
|
|
25
|
+
this.subs.delete(element);
|
|
26
|
+
if (this.subs.size === 0)
|
|
27
|
+
this.stop();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
start() {
|
|
31
|
+
if (typeof window === "undefined")
|
|
32
|
+
return;
|
|
33
|
+
window.addEventListener("scroll", this.scheduler, { passive: true });
|
|
34
|
+
window.addEventListener("resize", this.scheduler, { passive: true });
|
|
35
|
+
this.listening = true;
|
|
36
|
+
}
|
|
37
|
+
stop() {
|
|
38
|
+
if (typeof window === "undefined")
|
|
39
|
+
return;
|
|
40
|
+
window.removeEventListener("scroll", this.scheduler);
|
|
41
|
+
window.removeEventListener("resize", this.scheduler);
|
|
42
|
+
if (this.rafId !== null) {
|
|
43
|
+
cancelAnimationFrame(this.rafId);
|
|
44
|
+
this.rafId = null;
|
|
45
|
+
}
|
|
46
|
+
this.listening = false;
|
|
47
|
+
}
|
|
48
|
+
scheduleUpdate() {
|
|
49
|
+
if (this.rafId !== null)
|
|
50
|
+
return;
|
|
51
|
+
if (typeof requestAnimationFrame === "undefined")
|
|
52
|
+
return;
|
|
53
|
+
this.rafId = requestAnimationFrame(() => {
|
|
54
|
+
this.rafId = null;
|
|
55
|
+
this.flush();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Run every subscriber's callback with the current viewport + element
|
|
60
|
+
* rect. Exposed for tests that need deterministic flushes without
|
|
61
|
+
* waiting on rAF.
|
|
62
|
+
*/
|
|
63
|
+
flush() {
|
|
64
|
+
if (typeof window === "undefined")
|
|
65
|
+
return;
|
|
66
|
+
const viewport = {
|
|
67
|
+
width: window.innerWidth,
|
|
68
|
+
height: window.innerHeight,
|
|
69
|
+
};
|
|
70
|
+
for (const [el, sub] of this.subs) {
|
|
71
|
+
sub.onScroll(el.getBoundingClientRect(), viewport);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
let _shared = null;
|
|
76
|
+
/** Lazy singleton — first call creates the observer. SSR-safe. */
|
|
77
|
+
export function sharedScrollObserver() {
|
|
78
|
+
if (!_shared)
|
|
79
|
+
_shared = new ScrollObserver();
|
|
80
|
+
return _shared;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=observer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer.js","sourceRoot":"","sources":["../src/observer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,MAAM,OAAO,cAAc;IACjB,IAAI,GAAG,IAAI,GAAG,EAAiC,CAAC;IAChD,SAAS,GAAG,KAAK,CAAC;IAClB,KAAK,GAAkB,IAAI,CAAC;IACnB,SAAS,CAAa;IAEvC;QACE,IAAI,CAAC,SAAS,GAAG,GAAS,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;IACrD,CAAC;IAED,SAAS,CAAC,OAAoB,EAAE,UAA4B;QAC1D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC1B,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC;gBAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QACxC,CAAC,CAAC;IACJ,CAAC;IAEO,KAAK;QACX,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QAC1C,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAEO,IAAI;QACV,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QAC1C,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAEO,cAAc;QACpB,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO;QAChC,IAAI,OAAO,qBAAqB,KAAK,WAAW;YAAE,OAAO;QACzD,IAAI,CAAC,KAAK,GAAG,qBAAqB,CAAC,GAAG,EAAE;YACtC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK;QACH,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QAC1C,MAAM,QAAQ,GAAG;YACf,KAAK,EAAE,MAAM,CAAC,UAAU;YACxB,MAAM,EAAE,MAAM,CAAC,WAAW;SAClB,CAAC;QACX,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAClC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,qBAAqB,EAAE,EAAE,QAAQ,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;CACF;AAED,IAAI,OAAO,GAA0B,IAAI,CAAC;AAE1C,kEAAkE;AAClE,MAAM,UAAU,oBAAoB;IAClC,IAAI,CAAC,OAAO;QAAE,OAAO,GAAG,IAAI,cAAc,EAAE,CAAC;IAC7C,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Handle, ScrollProgressOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Emits a continuous [0, 1] value as `element` sweeps across the viewport.
|
|
4
|
+
*
|
|
5
|
+
* progress = 0 → element's top edge is at the viewport's bottom edge
|
|
6
|
+
* (element has just entered from below)
|
|
7
|
+
* progress = 1 → element's bottom edge is at the viewport's top edge
|
|
8
|
+
* (element has just exited through the top)
|
|
9
|
+
*
|
|
10
|
+
* The curve is linear by default; pass `ease: (t) => ...` to remap —
|
|
11
|
+
* any easing from `@vysmo/easings` works without importing it here.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createScrollProgress(options: ScrollProgressOptions): Handle;
|
|
14
|
+
//# sourceMappingURL=progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,GAC7B,MAAM,CAsBR"}
|
package/dist/progress.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { sharedScrollObserver } from "./observer.js";
|
|
2
|
+
/**
|
|
3
|
+
* Emits a continuous [0, 1] value as `element` sweeps across the viewport.
|
|
4
|
+
*
|
|
5
|
+
* progress = 0 → element's top edge is at the viewport's bottom edge
|
|
6
|
+
* (element has just entered from below)
|
|
7
|
+
* progress = 1 → element's bottom edge is at the viewport's top edge
|
|
8
|
+
* (element has just exited through the top)
|
|
9
|
+
*
|
|
10
|
+
* The curve is linear by default; pass `ease: (t) => ...` to remap —
|
|
11
|
+
* any easing from `@vysmo/easings` works without importing it here.
|
|
12
|
+
*/
|
|
13
|
+
export function createScrollProgress(options) {
|
|
14
|
+
const observer = sharedScrollObserver();
|
|
15
|
+
let lastProgress = Number.NaN;
|
|
16
|
+
const unsubscribe = observer.subscribe(options.element, {
|
|
17
|
+
onScroll(rect, viewport) {
|
|
18
|
+
const span = viewport.height + rect.height;
|
|
19
|
+
if (span <= 0)
|
|
20
|
+
return;
|
|
21
|
+
const raw = (viewport.height - rect.top) / span;
|
|
22
|
+
const clamped = raw < 0 ? 0 : raw > 1 ? 1 : raw;
|
|
23
|
+
const mapped = options.ease ? options.ease(clamped) : clamped;
|
|
24
|
+
if (mapped === lastProgress)
|
|
25
|
+
return;
|
|
26
|
+
lastProgress = mapped;
|
|
27
|
+
options.onProgress(mapped);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
destroy() {
|
|
32
|
+
unsubscribe();
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAGrD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAA8B;IAE9B,MAAM,QAAQ,GAAG,oBAAoB,EAAE,CAAC;IACxC,IAAI,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC;IAE9B,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE;QACtD,QAAQ,CAAC,IAAI,EAAE,QAAQ;YACrB,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YAC3C,IAAI,IAAI,IAAI,CAAC;gBAAE,OAAO;YACtB,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YAChD,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAChD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9D,IAAI,MAAM,KAAK,YAAY;gBAAE,OAAO;YACpC,YAAY,GAAG,MAAM,CAAC;YACtB,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,OAAO;YACL,WAAW,EAAE,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Effect, Runner, TextureSource, UniformParams } from "@vysmo/effects";
|
|
2
|
+
import type { EaseFn, Handle } from "./types.js";
|
|
3
|
+
export interface ScrollEffectOptions<P extends UniformParams> {
|
|
4
|
+
/**
|
|
5
|
+
* Section whose scroll-past drives the effect. Progress spans the
|
|
6
|
+
* full viewport sweep, same as `createScrollProgress`.
|
|
7
|
+
*/
|
|
8
|
+
section: HTMLElement;
|
|
9
|
+
/** Effects runner; caller owns the canvas + WebGL context. */
|
|
10
|
+
runner: Runner;
|
|
11
|
+
/** Effect to render on every scroll frame. */
|
|
12
|
+
effect: Effect<P>;
|
|
13
|
+
/** Source texture to filter — image, video, canvas. */
|
|
14
|
+
source: TextureSource;
|
|
15
|
+
/**
|
|
16
|
+
* Maps the scroll progress [0, 1] to the effect's uniform params.
|
|
17
|
+
* Keeps the scroll package free of effect-specific knowledge — the
|
|
18
|
+
* caller decides which param to animate and how.
|
|
19
|
+
*
|
|
20
|
+
* paramsAt: (p) => ({ radius: p * 20 })
|
|
21
|
+
*/
|
|
22
|
+
paramsAt: (progress: number) => Partial<P>;
|
|
23
|
+
/** Remap the raw [0, 1] progress before it reaches `paramsAt`. */
|
|
24
|
+
ease?: EaseFn;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Bind the scroll position through `section` to a continuous render of
|
|
28
|
+
* `effect` on `runner`, where the effect's params are a function of
|
|
29
|
+
* progress. Typical use: blur / chromatic-aberration / colour-grade
|
|
30
|
+
* intensity ramps up as the user scrolls into a section and back down
|
|
31
|
+
* as they scroll out.
|
|
32
|
+
*
|
|
33
|
+
* Same ownership model as `createScrollTransition`: you pass a Runner,
|
|
34
|
+
* scroll drives its `render()`. No re-render when progress is unchanged.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createScrollEffect<P extends UniformParams>(options: ScrollEffectOptions<P>): Handle;
|
|
37
|
+
//# sourceMappingURL=scroll-effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-effect.d.ts","sourceRoot":"","sources":["../src/scroll-effect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,MAAM,EACN,aAAa,EACb,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,aAAa;IAC1D;;;OAGG;IACH,OAAO,EAAE,WAAW,CAAC;IACrB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAClB,uDAAuD;IACvD,MAAM,EAAE,aAAa,CAAC;IACtB;;;;;;OAMG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3C,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,aAAa,EACxD,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAC9B,MAAM,CA0BR"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { sharedScrollObserver } from "./observer.js";
|
|
2
|
+
/**
|
|
3
|
+
* Bind the scroll position through `section` to a continuous render of
|
|
4
|
+
* `effect` on `runner`, where the effect's params are a function of
|
|
5
|
+
* progress. Typical use: blur / chromatic-aberration / colour-grade
|
|
6
|
+
* intensity ramps up as the user scrolls into a section and back down
|
|
7
|
+
* as they scroll out.
|
|
8
|
+
*
|
|
9
|
+
* Same ownership model as `createScrollTransition`: you pass a Runner,
|
|
10
|
+
* scroll drives its `render()`. No re-render when progress is unchanged.
|
|
11
|
+
*/
|
|
12
|
+
export function createScrollEffect(options) {
|
|
13
|
+
const observer = sharedScrollObserver();
|
|
14
|
+
let lastProgress = Number.NaN;
|
|
15
|
+
const unsubscribe = observer.subscribe(options.section, {
|
|
16
|
+
onScroll(rect, viewport) {
|
|
17
|
+
const span = viewport.height + rect.height;
|
|
18
|
+
if (span <= 0)
|
|
19
|
+
return;
|
|
20
|
+
const raw = (viewport.height - rect.top) / span;
|
|
21
|
+
const clamped = raw < 0 ? 0 : raw > 1 ? 1 : raw;
|
|
22
|
+
const mapped = options.ease ? options.ease(clamped) : clamped;
|
|
23
|
+
if (mapped === lastProgress)
|
|
24
|
+
return;
|
|
25
|
+
lastProgress = mapped;
|
|
26
|
+
const params = options.paramsAt(mapped);
|
|
27
|
+
options.runner.render(options.effect, {
|
|
28
|
+
source: options.source,
|
|
29
|
+
params,
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
destroy() {
|
|
35
|
+
unsubscribe();
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=scroll-effect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-effect.js","sourceRoot":"","sources":["../src/scroll-effect.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AA2BrD;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAA+B;IAE/B,MAAM,QAAQ,GAAG,oBAAoB,EAAE,CAAC;IACxC,IAAI,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC;IAE9B,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE;QACtD,QAAQ,CAAC,IAAI,EAAE,QAAQ;YACrB,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YAC3C,IAAI,IAAI,IAAI,CAAC;gBAAE,OAAO;YACtB,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YAChD,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAChD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9D,IAAI,MAAM,KAAK,YAAY;gBAAE,OAAO;YACpC,YAAY,GAAG,MAAM,CAAC;YACtB,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACxC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE;gBACpC,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,MAAM;aACP,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,OAAO;YACL,WAAW,EAAE,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Runner, TextureSource, Transition, UniformParams } from "@vysmo/transitions";
|
|
2
|
+
import type { EaseFn, Handle } from "./types.js";
|
|
3
|
+
export interface ScrollTransitionOptions<P extends UniformParams> {
|
|
4
|
+
/**
|
|
5
|
+
* Section whose scroll-past drives the transition. Progress is 0 when
|
|
6
|
+
* the section's top enters the viewport bottom and 1 when its bottom
|
|
7
|
+
* exits the viewport top — same curve as `createScrollProgress`.
|
|
8
|
+
*/
|
|
9
|
+
section: HTMLElement;
|
|
10
|
+
/**
|
|
11
|
+
* Transitions runner. The caller owns the WebGL context and its
|
|
12
|
+
* canvas — that keeps this primitive composable (multiple
|
|
13
|
+
* scroll-transitions can share one runner) and decouples lifecycle.
|
|
14
|
+
*/
|
|
15
|
+
runner: Runner;
|
|
16
|
+
/** Transition to render across the scroll range. */
|
|
17
|
+
transition: Transition<P>;
|
|
18
|
+
/** Starting source — shown at progress 0. */
|
|
19
|
+
from: TextureSource;
|
|
20
|
+
/** Ending source — shown at progress 1. */
|
|
21
|
+
to: TextureSource;
|
|
22
|
+
/** Overrides for the transition's uniform params. */
|
|
23
|
+
params?: Partial<P>;
|
|
24
|
+
/** Remap the raw [0, 1] progress. Default: linear. */
|
|
25
|
+
ease?: EaseFn;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Bind the vertical scroll position through `section` to a full transition
|
|
29
|
+
* run on `runner`. As the section sweeps past the viewport, `from` morphs
|
|
30
|
+
* into `to` via the chosen transition. One rAF per scroll frame, no
|
|
31
|
+
* re-render when the clamped progress hasn't changed.
|
|
32
|
+
*
|
|
33
|
+
* The scroll package does not import the transitions runtime — only its
|
|
34
|
+
* types. You pass in your own `Runner`, so the transitions library only
|
|
35
|
+
* lands in bundles that actually call this primitive.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createScrollTransition<P extends UniformParams>(options: ScrollTransitionOptions<P>): Handle;
|
|
38
|
+
//# sourceMappingURL=scroll-transition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-transition.d.ts","sourceRoot":"","sources":["../src/scroll-transition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,aAAa,EACd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS,aAAa;IAC9D;;;;OAIG;IACH,OAAO,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAC1B,6CAA6C;IAC7C,IAAI,EAAE,aAAa,CAAC;IACpB,2CAA2C;IAC3C,EAAE,EAAE,aAAa,CAAC;IAClB,qDAAqD;IACrD,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,aAAa,EAC5D,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAClC,MAAM,CAiCR"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { sharedScrollObserver } from "./observer.js";
|
|
2
|
+
/**
|
|
3
|
+
* Bind the vertical scroll position through `section` to a full transition
|
|
4
|
+
* run on `runner`. As the section sweeps past the viewport, `from` morphs
|
|
5
|
+
* into `to` via the chosen transition. One rAF per scroll frame, no
|
|
6
|
+
* re-render when the clamped progress hasn't changed.
|
|
7
|
+
*
|
|
8
|
+
* The scroll package does not import the transitions runtime — only its
|
|
9
|
+
* types. You pass in your own `Runner`, so the transitions library only
|
|
10
|
+
* lands in bundles that actually call this primitive.
|
|
11
|
+
*/
|
|
12
|
+
export function createScrollTransition(options) {
|
|
13
|
+
const observer = sharedScrollObserver();
|
|
14
|
+
let lastProgress = Number.NaN;
|
|
15
|
+
const unsubscribe = observer.subscribe(options.section, {
|
|
16
|
+
onScroll(rect, viewport) {
|
|
17
|
+
const span = viewport.height + rect.height;
|
|
18
|
+
if (span <= 0)
|
|
19
|
+
return;
|
|
20
|
+
const raw = (viewport.height - rect.top) / span;
|
|
21
|
+
const clamped = raw < 0 ? 0 : raw > 1 ? 1 : raw;
|
|
22
|
+
const mapped = options.ease ? options.ease(clamped) : clamped;
|
|
23
|
+
if (mapped === lastProgress)
|
|
24
|
+
return;
|
|
25
|
+
lastProgress = mapped;
|
|
26
|
+
const args = {
|
|
27
|
+
from: options.from,
|
|
28
|
+
to: options.to,
|
|
29
|
+
progress: mapped,
|
|
30
|
+
};
|
|
31
|
+
if (options.params !== undefined)
|
|
32
|
+
args.params = options.params;
|
|
33
|
+
options.runner.render(options.transition, args);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
destroy() {
|
|
38
|
+
unsubscribe();
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=scroll-transition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-transition.js","sourceRoot":"","sources":["../src/scroll-transition.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AA4BrD;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAmC;IAEnC,MAAM,QAAQ,GAAG,oBAAoB,EAAE,CAAC;IACxC,IAAI,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC;IAE9B,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE;QACtD,QAAQ,CAAC,IAAI,EAAE,QAAQ;YACrB,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YAC3C,IAAI,IAAI,IAAI,CAAC;gBAAE,OAAO;YACtB,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YAChD,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAChD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9D,IAAI,MAAM,KAAK,YAAY;gBAAE,OAAO;YACpC,YAAY,GAAG,MAAM,CAAC;YACtB,MAAM,IAAI,GAKN;gBACF,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,QAAQ,EAAE,MAAM;aACjB,CAAC;YACF,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC/D,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAClD,CAAC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,OAAO;YACL,WAAW,EAAE,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Signature compatible with `@vysmo/easings.EasingFn`, kept local so this package has zero runtime coupling to the easings lib. */
|
|
2
|
+
export type EaseFn = (t: number) => number;
|
|
3
|
+
export interface Handle {
|
|
4
|
+
destroy(): void;
|
|
5
|
+
}
|
|
6
|
+
export interface ScrollProgressOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Element whose bounding box is tracked. Progress is 0 when its top is
|
|
9
|
+
* at the viewport bottom and 1 when its bottom is at the viewport top
|
|
10
|
+
* — i.e. a full sweep across the viewport.
|
|
11
|
+
*/
|
|
12
|
+
element: HTMLElement;
|
|
13
|
+
/** Remap the raw [0, 1] progress. Default: linear. */
|
|
14
|
+
ease?: EaseFn;
|
|
15
|
+
/** Invoked on every frame the element's position changes. */
|
|
16
|
+
onProgress: (progress: number) => void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oIAAoI;AACpI,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAE3C,MAAM,WAAW,MAAM;IACrB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,OAAO,EAAE,WAAW,CAAC;IACrB,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/zones.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { EaseFn } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Smoothstep — `t² · (3 − 2t)`. C1-continuous S-curve that matches
|
|
4
|
+
* linear at 0, 0.5, and 1 but eases in and out near the boundaries.
|
|
5
|
+
* Used as the default ramp shape for every zone helper so transitions
|
|
6
|
+
* and effects decelerate smoothly into their plateaus instead of
|
|
7
|
+
* snapping on the derivative discontinuity of a pure linear ramp.
|
|
8
|
+
*
|
|
9
|
+
* Exported so callers can reach for it explicitly, or compose it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const smoothstep: EaseFn;
|
|
12
|
+
/**
|
|
13
|
+
* Clamp progress to a sub-range. Outside the range, the output stays flat
|
|
14
|
+
* (0 before `start`, 1 after `end`). Inside, progress is remapped from
|
|
15
|
+
* `[start, end]` to `[0, 1]` through the supplied ease (default:
|
|
16
|
+
* {@link smoothstep}).
|
|
17
|
+
*
|
|
18
|
+
* scrollRange(0.1, 0.5) — transition plays between 10% and 50% of the
|
|
19
|
+
* full viewport sweep; does nothing before, stays at its final state
|
|
20
|
+
* after. Pass `ease: (t) => t` for a linear clamp.
|
|
21
|
+
*
|
|
22
|
+
* Designed for `createScrollTransition` so the transition completes at a
|
|
23
|
+
* point the author chooses — typically well before the section exits the
|
|
24
|
+
* viewport — and then holds its final state while the user keeps scrolling.
|
|
25
|
+
*/
|
|
26
|
+
export declare function scrollRange(start: number, end: number, ease?: EaseFn): EaseFn;
|
|
27
|
+
/**
|
|
28
|
+
* Three-zone bathtub envelope for effects.
|
|
29
|
+
*
|
|
30
|
+
* scrollZones(0.25, 0.85) — effect ramps from max at `p = 0` down to
|
|
31
|
+
* zero at `p = 0.25` (smoothly by default), stays at zero through the
|
|
32
|
+
* clear zone (`0.25 ≤ p ≤ 0.85`), then ramps back up to max by
|
|
33
|
+
* `p = 1`.
|
|
34
|
+
*
|
|
35
|
+
* Designed for `createScrollEffect` where "identity" is zero intensity —
|
|
36
|
+
* so the image reads cleanly while the section is visible and the effect
|
|
37
|
+
* only appears as it enters and exits the viewport. Pass `ease: (t) => t`
|
|
38
|
+
* for a linear ramp; default is {@link smoothstep}.
|
|
39
|
+
*/
|
|
40
|
+
export declare function scrollZones(clearStart: number, clearEnd: number, ease?: EaseFn): EaseFn;
|
|
41
|
+
/**
|
|
42
|
+
* Three-zone plateau envelope — the inverse of {@link scrollZones}.
|
|
43
|
+
*
|
|
44
|
+
* scrollPlateau(0.3, 0.7) — rises from 0 at `p = 0` up to 1 at
|
|
45
|
+
* `p = 0.3` (smoothly by default), holds at 1 across the clear zone
|
|
46
|
+
* (`0.3 ≤ p ≤ 0.7`), then falls back to 0 by `p = 1`.
|
|
47
|
+
*
|
|
48
|
+
* Designed for `createScrollTransition` where "identity" is the fully
|
|
49
|
+
* transitioned state (progress 1). The transition plays in as the
|
|
50
|
+
* section enters, holds its final frame across the clear zone, then
|
|
51
|
+
* plays back out (reverse) as the section exits. Smoothstep default
|
|
52
|
+
* prevents the harsh snap that a linear ramp produces at the plateau
|
|
53
|
+
* boundaries.
|
|
54
|
+
*/
|
|
55
|
+
export declare function scrollPlateau(clearStart: number, clearEnd: number, ease?: EaseFn): EaseFn;
|
|
56
|
+
//# sourceMappingURL=zones.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zones.d.ts","sourceRoot":"","sources":["../src/zones.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,EAAE,MAAmC,CAAC;AAE7D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,MAAmB,GACxB,MAAM,CAQR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAmB,GACxB,MAAM,CAYR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAmB,GACxB,MAAM,CAYR"}
|