use-scroll-animate 1.2.0 → 1.5.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.
@@ -1,123 +1,153 @@
1
- /**
2
- * use-scroll-animate - Core Type Definitions
3
- * A lightweight, high-performance scroll animation library
4
- */
5
- /** Built-in animation presets */
6
- export type AnimationPreset = 'fade-in' | 'fade-in-up' | 'fade-in-down' | 'fade-in-left' | 'fade-in-right' | 'zoom-in' | 'zoom-out' | 'flip-x' | 'flip-y' | 'slide-up' | 'slide-down' | 'slide-left' | 'slide-right' | 'bounce' | 'rotate-in' | 'blur-in' | 'skew-in' | 'scale-x' | 'scale-y' | 'shimmer' | 'pulse' | 'swing';
7
- /** Easing function types */
8
- export type EasingType = 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring' | string;
9
- /** Keyframe definition for custom animations */
10
- export interface AnimationKeyframe {
11
- [property: string]: string | number;
12
- }
13
- /** Custom animation definition */
14
- export interface CustomAnimation {
15
- from: AnimationKeyframe;
16
- to: AnimationKeyframe;
17
- }
18
- /** Parallax configuration */
19
- export interface ParallaxOptions {
20
- /** Movement on X axis (e.g., '100px', '20%') */
21
- x?: string | number;
22
- /** Movement on Y axis (e.g., '100px', '20%') */
23
- y?: string | number;
24
- /** Rotation in degrees */
25
- rotate?: number;
26
- /** Scale factor */
27
- scale?: number;
28
- /** Speed multiplier (default: 1) */
29
- speed?: number;
30
- }
31
- /** Per-element animation options */
32
- export interface AnimateOptions {
33
- /** Animation preset name, array of presets, or custom animation object */
34
- animation?: AnimationPreset | AnimationPreset[] | CustomAnimation;
35
- /** Duration in milliseconds (default: 600) */
36
- duration?: number;
37
- /** Delay in milliseconds (default: 0) */
38
- delay?: number;
39
- /** Easing function (default: 'ease') */
40
- easing?: EasingType;
41
- /** Intersection threshold 0-1 (default: 0.1) */
42
- threshold?: number | number[];
43
- /** Root margin for IntersectionObserver (default: '0px') */
44
- rootMargin?: string;
45
- /** Whether to replay animation each time element enters viewport (default: false) */
46
- repeat?: boolean;
47
- /** Whether to trigger animation only once (default: true if repeat is false) */
48
- once?: boolean;
49
- /** Offset in pixels from the viewport edge to trigger animation (default: 0) */
50
- offset?: number;
51
- /** Stagger delay for child elements in ms (default: 0) */
52
- stagger?: number;
53
- /** Parallax effect configuration */
54
- parallax?: ParallaxOptions;
55
- /** Callback fired when animation starts */
56
- onStart?: (element: Element) => void;
57
- /** Callback fired when animation completes */
58
- onComplete?: (element: Element) => void;
59
- /** Callback fired when element enters viewport */
60
- onEnter?: (element: Element) => void;
61
- /** Callback fired when element leaves viewport */
62
- onLeave?: (element: Element) => void;
63
- /** Callback fired with scroll progress (0 to 1) */
64
- onProgress?: (element: Element, progress: number) => void;
65
- }
66
- /** Global configuration for ScrollAnimate instance */
67
- export interface ScrollAnimateConfig {
68
- /** Default animation preset (default: 'fade-in-up') */
69
- defaultAnimation?: AnimationPreset | AnimationPreset[] | CustomAnimation;
70
- /** Default duration in ms (default: 600) */
71
- defaultDuration?: number;
72
- /** Default delay in ms (default: 0) */
73
- defaultDelay?: number;
74
- /** Default easing (default: 'ease') */
75
- defaultEasing?: EasingType;
76
- /** Default threshold (default: 0.1) */
77
- defaultThreshold?: number | number[];
78
- /** Default root margin (default: '0px') */
79
- defaultRootMargin?: string;
80
- /** Whether animations replay by default (default: false) */
81
- defaultRepeat?: boolean;
82
- /** Default once setting (default: true) */
83
- defaultOnce?: boolean;
84
- /** Default offset in pixels (default: 0) */
85
- defaultOffset?: number;
86
- /** CSS class added before animation (default: 'sa-hidden') */
87
- hiddenClass?: string;
88
- /** CSS class added when element is visible (default: 'sa-visible') */
89
- visibleClass?: string;
90
- /** Whether to use CSS class-based animation instead of Web Animations API */
91
- useClassNames?: boolean;
92
- /** Disable all animations (useful for reduced-motion preference) */
93
- disabled?: boolean;
94
- /** Custom IntersectionObserver root element */
95
- root?: Element | null;
96
- }
97
- /** Registered element entry */
98
- export interface AnimatedElement {
99
- element: Element;
100
- options: Required<AnimateOptions>;
101
- observer: IntersectionObserver;
102
- animated: boolean;
103
- progressObserver?: IntersectionObserver;
104
- }
105
- /** ScrollAnimate public API */
106
- export interface ScrollAnimateInstance {
107
- /** Observe a single element or CSS selector */
108
- observe(target: string | Element | NodeList | Element[], options?: AnimateOptions): void;
109
- /** Stop observing a single element or CSS selector */
110
- unobserve(target: string | Element | NodeList | Element[]): void;
111
- /** Observe all elements matching the data-sa attribute */
112
- init(rootElement?: Element | Document): void;
113
- /** Destroy the instance and clean up all observers */
114
- destroy(): void;
115
- /** Refresh all observers (useful after DOM changes) */
116
- refresh(): void;
117
- /** Manually trigger animation on an element */
118
- animate(target: string | Element, options?: AnimateOptions): void;
119
- /** Get all currently observed elements */
120
- getObservedElements(): AnimatedElement[];
121
- /** Update global configuration */
122
- configure(config: Partial<ScrollAnimateConfig>): void;
123
- }
1
+ /**
2
+ * use-scroll-animate - Core Type Definitions
3
+ * A lightweight, high-performance scroll animation library
4
+ */
5
+ /** Built-in animation presets */
6
+ export type AnimationPreset = 'fade-in' | 'fade-in-up' | 'fade-in-down' | 'fade-in-left' | 'fade-in-right' | 'zoom-in' | 'zoom-out' | 'flip-x' | 'flip-y' | 'slide-up' | 'slide-down' | 'slide-left' | 'slide-right' | 'bounce' | 'rotate-in' | 'blur-in' | 'skew-in' | 'scale-x' | 'scale-y' | 'shimmer' | 'pulse' | 'swing' | 'scale-up' | 'blur-in-up' | 'flip-up' | 'flip-down' | 'rotate-left' | 'rotate-right' | 'clip-up' | 'clip-down' | 'clip-left' | 'clip-right' | 'clip-circle';
7
+ /**
8
+ * How `onProgress` (and parallax) progress is measured.
9
+ * - `'ratio'` (default): the element's visible ratio (IntersectionObserver `intersectionRatio`).
10
+ * - `'scroll'`: true scroll progress, 0 when the element's top touches the bottom of the
11
+ * viewport and 1 when its bottom leaves the top. Works for elements taller than the screen.
12
+ */
13
+ export type ProgressMode = 'ratio' | 'scroll';
14
+ /** Easing function types */
15
+ export type EasingType = 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring' | 'soft-spring' | 'heavy-bounce' | [number, number, number, number] | ((t: number) => number) | string;
16
+ /** Keyframe definition for custom animations */
17
+ export interface AnimationKeyframe {
18
+ [property: string]: string | number;
19
+ }
20
+ /** Custom animation definition */
21
+ export interface CustomAnimation {
22
+ from: AnimationKeyframe;
23
+ to: AnimationKeyframe;
24
+ }
25
+ /** Parallax configuration */
26
+ export interface ParallaxOptions {
27
+ /** Movement on X axis (e.g., '100px', '20%') */
28
+ x?: string | number;
29
+ /** Movement on Y axis (e.g., '100px', '20%') */
30
+ y?: string | number;
31
+ /** Rotation in degrees */
32
+ rotate?: number;
33
+ /** Scale factor */
34
+ scale?: number;
35
+ /** Speed multiplier (default: 1) */
36
+ speed?: number;
37
+ }
38
+ /** Per-element animation options */
39
+ export interface AnimateOptions {
40
+ /** Animation preset name, array of presets, or custom animation object */
41
+ animation?: AnimationPreset | AnimationPreset[] | CustomAnimation;
42
+ /** Duration in milliseconds (default: 600) */
43
+ duration?: number;
44
+ /** Delay in milliseconds (default: 0) */
45
+ delay?: number;
46
+ /** Easing function (default: 'ease') */
47
+ easing?: EasingType;
48
+ /** Intersection threshold 0-1 (default: 0.1) */
49
+ threshold?: number | number[];
50
+ /** Root margin for IntersectionObserver (default: '0px') */
51
+ rootMargin?: string;
52
+ /** Whether to replay animation each time element enters viewport (default: false) */
53
+ repeat?: boolean;
54
+ /** Whether to trigger animation only once (default: true if repeat is false) */
55
+ once?: boolean;
56
+ /** Offset in pixels from the viewport edge to trigger animation (default: 0) */
57
+ offset?: number;
58
+ /** Stagger delay for child elements in ms (default: 0) */
59
+ stagger?: number;
60
+ /** Parallax effect configuration */
61
+ parallax?: ParallaxOptions;
62
+ /** Callback fired when animation starts */
63
+ onStart?: (element: Element) => void;
64
+ /** Callback fired when animation completes */
65
+ onComplete?: (element: Element) => void;
66
+ /** Callback fired when element enters viewport */
67
+ onEnter?: (element: Element) => void;
68
+ /** Callback fired when element leaves viewport */
69
+ onLeave?: (element: Element) => void;
70
+ /** Callback fired with scroll progress (0 to 1) */
71
+ onProgress?: (element: Element, progress: number) => void;
72
+ /** How progress for `onProgress`/parallax is measured (default: 'ratio') */
73
+ progressMode?: ProgressMode;
74
+ /**
75
+ * Name of a CSS custom property (e.g. `'--sa-progress'`) that receives the
76
+ * element's progress (0 to 1, same value as `onProgress`) as an inline
77
+ * style, for scroll-driven effects written in plain CSS. Off by default.
78
+ */
79
+ progressVar?: string;
80
+ }
81
+ /** Global configuration for ScrollAnimate instance */
82
+ export interface ScrollAnimateConfig {
83
+ /** Default animation preset (default: 'fade-in-up') */
84
+ defaultAnimation?: AnimationPreset | AnimationPreset[] | CustomAnimation;
85
+ /** Default duration in ms (default: 600) */
86
+ defaultDuration?: number;
87
+ /** Default delay in ms (default: 0) */
88
+ defaultDelay?: number;
89
+ /** Default easing (default: 'ease') */
90
+ defaultEasing?: EasingType;
91
+ /** Default threshold (default: 0.1) */
92
+ defaultThreshold?: number | number[];
93
+ /** Default root margin (default: '0px') */
94
+ defaultRootMargin?: string;
95
+ /** Whether animations replay by default (default: false) */
96
+ defaultRepeat?: boolean;
97
+ /** Default once setting (default: true) */
98
+ defaultOnce?: boolean;
99
+ /** Default offset in pixels (default: 0) */
100
+ defaultOffset?: number;
101
+ /** CSS class added before animation (default: 'sa-hidden') */
102
+ hiddenClass?: string;
103
+ /** CSS class added when element is visible (default: 'sa-visible') */
104
+ visibleClass?: string;
105
+ /** Whether to use CSS class-based animation instead of Web Animations API */
106
+ useClassNames?: boolean;
107
+ /** Disable all animations (useful for reduced-motion preference) */
108
+ disabled?: boolean;
109
+ /** Custom IntersectionObserver root element */
110
+ root?: Element | null;
111
+ /**
112
+ * Drop `once` elements from the registry as soon as their entrance animation
113
+ * has been triggered (unless they still need parallax/onProgress), so they can
114
+ * be garbage-collected. They are remembered in a WeakSet, so `init()`/`observe()`
115
+ * never re-hide or replay them. (default: true)
116
+ */
117
+ autoUnregister?: boolean;
118
+ }
119
+ /** Registered element entry */
120
+ export interface AnimatedElement {
121
+ element: Element;
122
+ options: Required<AnimateOptions>;
123
+ observer: IntersectionObserver;
124
+ animated: boolean;
125
+ progressObserver?: IntersectionObserver;
126
+ }
127
+ /** ScrollAnimate public API */
128
+ export interface ScrollAnimateInstance {
129
+ /** Observe a single element or CSS selector */
130
+ observe(target: string | Element | NodeList | Element[], options?: AnimateOptions): void;
131
+ /** Stop observing a single element or CSS selector */
132
+ unobserve(target: string | Element | NodeList | Element[]): void;
133
+ /** Observe all elements matching the data-sa attribute */
134
+ init(rootElement?: Element | Document): void;
135
+ /**
136
+ * Like `init()`, then keep watching `rootElement` (default: `document`) with a
137
+ * MutationObserver: `[data-sa]` elements added later (or that gain the
138
+ * attribute) are observed automatically, and removed ones are released.
139
+ * Returns a function that stops watching. `destroy()` stops every watcher.
140
+ * SSR-safe: a no-op without a DOM / MutationObserver.
141
+ */
142
+ watch(rootElement?: Element | Document): () => void;
143
+ /** Destroy the instance and clean up all observers */
144
+ destroy(): void;
145
+ /** Refresh all observers (useful after DOM changes) */
146
+ refresh(): void;
147
+ /** Manually trigger animation on an element */
148
+ animate(target: string | Element, options?: AnimateOptions): void;
149
+ /** Get all currently observed elements */
150
+ getObservedElements(): AnimatedElement[];
151
+ /** Update global configuration */
152
+ configure(config: Partial<ScrollAnimateConfig>): void;
153
+ }
@@ -1,18 +1,28 @@
1
- /**
2
- * use-scroll-animate - Vue 3 Integration
3
- * Provides useScrollAnimate composable for Vue 3 applications.
4
- */
5
- import type { AnimateOptions } from './types';
6
- export declare function createVueComposables(Vue: {
7
- ref: <T>(value: T | null) => {
8
- value: T | null;
9
- };
10
- onMounted: (fn: () => void) => void;
11
- onUnmounted: (fn: () => void) => void;
12
- }): {
13
- useScrollAnimate: (options?: AnimateOptions) => {
14
- animateRef: {
15
- value: Element | null;
16
- };
17
- };
18
- };
1
+ /**
2
+ * use-scroll-animate - Vue 3 Integration
3
+ * Provides useScrollAnimate and useScrollStagger composables for Vue 3 applications.
4
+ *
5
+ * A thin wrapper around the core engine, so it shares its behaviour: `once`,
6
+ * `offset`, custom easing functions, parallax, `prefers-reduced-motion`
7
+ * support, and cleanup on unmount.
8
+ */
9
+ import type { AnimateOptions } from './types';
10
+ import { type StaggerOptions } from './stagger';
11
+ export declare function createVueComposables(Vue: {
12
+ ref: <T>(value: T | null) => {
13
+ value: T | null;
14
+ };
15
+ onMounted: (fn: () => void) => void;
16
+ onUnmounted: (fn: () => void) => void;
17
+ }): {
18
+ useScrollAnimate: (options?: AnimateOptions) => {
19
+ animateRef: {
20
+ value: Element | null;
21
+ };
22
+ };
23
+ useScrollStagger: (options?: StaggerOptions) => {
24
+ staggerRef: {
25
+ value: Element | null;
26
+ };
27
+ };
28
+ };
package/package.json CHANGED
@@ -1,35 +1,81 @@
1
- {
2
- "name": "use-scroll-animate",
3
- "version": "1.2.0",
4
- "description": "A lightweight, high-performance, dependency-free scroll animation library for modern web.",
5
- "main": "dist/index.js",
6
- "module": "dist/index.esm.js",
7
- "browser": "dist/index.umd.js",
8
- "types": "dist/types/index.d.ts",
9
- "scripts": {
10
- "build": "rollup -c",
11
- "dev": "rollup -c -w",
12
- "test": "echo \"Error: no test specified\" && exit 1"
13
- },
14
- "keywords": [
15
- "scroll",
16
- "animation",
17
- "intersection-observer",
18
- "lightweight",
19
- "vanilla-js",
20
- "typescript",
21
- "frontend",
22
- "ui"
23
- ],
24
- "author": "",
25
- "license": "MIT",
26
- "devDependencies": {
27
- "@rollup/plugin-commonjs": "^29.0.2",
28
- "@rollup/plugin-node-resolve": "^16.0.3",
29
- "@rollup/plugin-terser": "^1.0.0",
30
- "@rollup/plugin-typescript": "^12.3.0",
31
- "rollup": "^4.60.0",
32
- "tslib": "^2.8.1",
33
- "typescript": "^6.0.2"
34
- }
35
- }
1
+ {
2
+ "name": "use-scroll-animate",
3
+ "version": "1.5.0",
4
+ "description": "A lightweight, high-performance, dependency-free scroll animation library for modern web.",
5
+ "type": "commonjs",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.esm.js",
8
+ "unpkg": "dist/index.umd.js",
9
+ "jsdelivr": "dist/index.umd.js",
10
+ "types": "dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": {
14
+ "types": "./dist/index.d.mts",
15
+ "default": "./dist/index.mjs"
16
+ },
17
+ "require": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ }
21
+ },
22
+ "./dist/*": "./dist/*",
23
+ "./package.json": "./package.json"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "README.md",
28
+ "README_zh.md",
29
+ "README_ja.md",
30
+ "LICENSE",
31
+ "CHANGELOG.md"
32
+ ],
33
+ "sideEffects": false,
34
+ "scripts": {
35
+ "build": "rollup -c",
36
+ "dev": "rollup -c -w",
37
+ "typecheck": "tsc --noEmit -p .",
38
+ "test": "vitest run",
39
+ "check:exports": "node scripts/check-exports.mjs",
40
+ "lint:package": "publint && attw --pack . --profile node16",
41
+ "size": "node scripts/size.mjs",
42
+ "prepublishOnly": "npm run typecheck && npm test && npm run build && npm run check:exports"
43
+ },
44
+ "keywords": [
45
+ "scroll",
46
+ "animation",
47
+ "intersection-observer",
48
+ "lightweight",
49
+ "vanilla-js",
50
+ "typescript",
51
+ "frontend",
52
+ "ui",
53
+ "scroll-progress",
54
+ "stagger",
55
+ "timeline"
56
+ ],
57
+ "author": "HarrisonCN",
58
+ "license": "MIT",
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "git+https://github.com/HarrisonCN/use-scroll-animate.git"
62
+ },
63
+ "bugs": {
64
+ "url": "https://github.com/HarrisonCN/use-scroll-animate/issues"
65
+ },
66
+ "homepage": "https://github.com/HarrisonCN/use-scroll-animate#readme",
67
+ "devDependencies": {
68
+ "@arethetypeswrong/cli": "^0.18.5",
69
+ "@rollup/plugin-commonjs": "^29.0.2",
70
+ "@rollup/plugin-node-resolve": "^16.0.3",
71
+ "@rollup/plugin-terser": "^1.0.0",
72
+ "@rollup/plugin-typescript": "^12.3.0",
73
+ "jsdom": "^26.1.0",
74
+ "publint": "^0.3.25",
75
+ "rollup": "^4.60.0",
76
+ "rollup-plugin-dts": "^6.5.1",
77
+ "tslib": "^2.8.1",
78
+ "typescript": "^6.0.2",
79
+ "vitest": "^3.2.7"
80
+ }
81
+ }
package/CONTRIBUTING.md DELETED
@@ -1,76 +0,0 @@
1
- # Contributing to use-scroll-animate
2
-
3
- First off, thank you for considering contributing to `use-scroll-animate`! It's people like you that make the open-source community such a great place to learn, inspire, and create.
4
-
5
- ## Code of Conduct
6
-
7
- By participating in this project, you are expected to uphold our Code of Conduct. Please treat everyone with respect and kindness.
8
-
9
- ## How Can I Contribute?
10
-
11
- ### Reporting Bugs
12
-
13
- Before creating bug reports, please check the issue tracker as you might find out that you don't need to create one. When you are creating a bug report, please include as many details as possible:
14
-
15
- * Use a clear and descriptive title for the issue to identify the problem.
16
- * Describe the exact steps which reproduce the problem in as many details as possible.
17
- * Provide specific examples to demonstrate the steps. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples.
18
- * Describe the behavior you observed after following the steps and point out what exactly is the problem with that behavior.
19
- * Explain which behavior you expected to see instead and why.
20
-
21
- ### Suggesting Enhancements
22
-
23
- Enhancement suggestions are tracked as GitHub issues. When you are creating an enhancement suggestion, please include:
24
-
25
- * Use a clear and descriptive title for the issue to identify the suggestion.
26
- * Provide a step-by-step description of the suggested enhancement in as many details as possible.
27
- * Provide specific examples to demonstrate the steps.
28
- * Describe the current behavior and explain which behavior you expected to see instead and why.
29
- * Explain why this enhancement would be useful to most users.
30
-
31
- ### Pull Requests
32
-
33
- 1. Fork the repo and create your branch from `main`.
34
- 2. If you've added code that should be tested, add tests.
35
- 3. If you've changed APIs, update the documentation.
36
- 4. Ensure the test suite passes.
37
- 5. Make sure your code lints.
38
- 6. Issue that pull request!
39
-
40
- ## Development Setup
41
-
42
- 1. Clone your fork:
43
- ```bash
44
- git clone https://github.com/YOUR-USERNAME/use-scroll-animate.git
45
- cd use-scroll-animate
46
- ```
47
-
48
- 2. Install dependencies:
49
- ```bash
50
- npm install
51
- ```
52
-
53
- 3. Start the development build watcher:
54
- ```bash
55
- npm run dev
56
- ```
57
-
58
- 4. Build the project:
59
- ```bash
60
- npm run build
61
- ```
62
-
63
- ## Commit Messages
64
-
65
- We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. Please ensure your commit messages adhere to this format:
66
-
67
- * `feat:` A new feature
68
- * `fix:` A bug fix
69
- * `docs:` Documentation only changes
70
- * `style:` Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
71
- * `refactor:` A code change that neither fixes a bug nor adds a feature
72
- * `perf:` A code change that improves performance
73
- * `test:` Adding missing tests or correcting existing tests
74
- * `chore:` Changes to the build process or auxiliary tools and libraries such as documentation generation
75
-
76
- Thank you for your contribution!
@@ -1,61 +0,0 @@
1
- /**
2
- * use-scroll-animate — React Example
3
- *
4
- * This example demonstrates how to use the useScrollAnimate and useScrollStagger
5
- * hooks in a React application.
6
- */
7
-
8
- import React from 'react';
9
- import { createReactHooks } from 'use-scroll-animate';
10
-
11
- const { useScrollAnimate, useScrollStagger } = createReactHooks(React);
12
-
13
- const features = [
14
- { title: 'Zero Dependencies', desc: 'No lodash, no jQuery, no bloat.' },
15
- { title: 'TypeScript First', desc: 'Full type safety and IntelliSense.' },
16
- { title: 'Framework Agnostic', desc: 'Works with React, Vue, Svelte, and more.' },
17
- { title: 'Accessible', desc: 'Respects prefers-reduced-motion.' },
18
- ];
19
-
20
- export default function App() {
21
- const heroTitleRef = useScrollAnimate({ animation: 'fade-in-down', duration: 1000 });
22
- const heroSubRef = useScrollAnimate({ animation: 'fade-in-up', delay: 300 });
23
- const featuresRef = useScrollStagger({ animation: 'fade-in-up', stagger: 120 });
24
- const ctaRef = useScrollAnimate({ animation: 'zoom-in', easing: 'spring' });
25
-
26
- return (
27
- <main style={{ fontFamily: 'system-ui, sans-serif', background: '#0a0a0a', color: '#fff', minHeight: '100vh' }}>
28
- {/* Hero Section */}
29
- <section style={{ height: '100vh', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', textAlign: 'center', padding: '2rem' }}>
30
- <h1 ref={heroTitleRef} style={{ fontSize: 'clamp(2rem, 6vw, 5rem)', fontWeight: 800 }}>
31
- use-scroll-animate
32
- </h1>
33
- <p ref={heroSubRef} style={{ fontSize: '1.2rem', color: '#aaa', marginTop: '1rem' }}>
34
- Lightweight. Dependency-free. Blazing fast.
35
- </p>
36
- </section>
37
-
38
- {/* Features Section */}
39
- <section style={{ maxWidth: 900, margin: '0 auto', padding: '6rem 2rem' }}>
40
- <ul ref={featuresRef} style={{ listStyle: 'none', padding: 0, display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1.5rem' }}>
41
- {features.map((f) => (
42
- <li key={f.title} style={{ background: '#1a1a1a', border: '1px solid #333', borderRadius: 12, padding: '1.5rem' }}>
43
- <h3 style={{ marginBottom: '0.5rem' }}>{f.title}</h3>
44
- <p style={{ color: '#aaa', lineHeight: 1.6 }}>{f.desc}</p>
45
- </li>
46
- ))}
47
- </ul>
48
- </section>
49
-
50
- {/* CTA Section */}
51
- <section style={{ textAlign: 'center', padding: '6rem 2rem' }}>
52
- <div ref={ctaRef} style={{ display: 'inline-block', background: 'linear-gradient(135deg, #6366f1, #8b5cf6)', borderRadius: 16, padding: '3rem 4rem' }}>
53
- <h2 style={{ fontSize: '2rem', marginBottom: '1rem' }}>Get Started Today</h2>
54
- <code style={{ background: 'rgba(0,0,0,0.3)', padding: '0.5rem 1rem', borderRadius: 8, fontSize: '1rem' }}>
55
- npm install use-scroll-animate
56
- </code>
57
- </div>
58
- </section>
59
- </main>
60
- );
61
- }