├── .DS_Store ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── css └── base.css ├── favicon.ico ├── img ├── .DS_Store ├── 1.jpg ├── 10.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg ├── 7.jpg ├── 8.jpg ├── 9.jpg └── noise.png ├── index.html └── js ├── .DS_Store ├── ScrollTrigger.min.js ├── effect-1 └── stackMotionEffect.js ├── effect-2 └── stackMotionEffect.js ├── effect-3 └── stackMotionEffect.js ├── gsap.min.js ├── imagesloaded.pkgd.min.js ├── index.js ├── lenis.js ├── smoothscroll.js └── utils.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .cache 3 | .parcel-cache 4 | package-lock.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2009 - 2024 [Codrops](https://tympanus.net/codrops) 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 3D Stack Motion on Scroll 2 | 3 | A [#3D](https://tympanus.net/codrops/demos/?tag=3d) [#stack](https://tympanus.net/codrops/demos/?tag=stack) motion effect on [#scroll](https://tympanus.net/codrops/demos/?tag=scroll) inspired by [Looksrare: NFT cards](https://dribbble.com/shots/23641913-Looksrare-NFT-cards). 4 | 5 | ![3D Stack Motion Effect](https://tympanus.net/codrops/wp-content/uploads/2024/03/3dstackmotion.jpg) 6 | 7 | [Article on Codrops](https://tympanus.net/codrops/?p=75974) 8 | 9 | [Demo](https://tympanus.net/Development/3DStackMotion/) 10 | 11 | ## Installation 12 | 13 | Run this demo on a [local server](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Tools_and_setup/set_up_a_local_testing_server). 14 | 15 | ## Credits 16 | 17 | - Images generated with [Midjourney](https://midjourney.com) 18 | 19 | ## Misc 20 | 21 | Follow Codrops: [X](http://www.X.com/codrops), [Facebook](http://www.facebook.com/codrops), [GitHub](https://github.com/codrops), [Instagram](https://www.instagram.com/codropsss/) 22 | 23 | Subscribe to our frontend newsletter: [The Collective](https://tympanus.net/codrops/collective/) 24 | 25 | Need help with your animations? You can [hire us](mailto:contact@codrops.com). 26 | 27 | ## License 28 | [MIT](LICENSE) 29 | 30 | Made with :blue_heart: by [Codrops](http://www.codrops.com) 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 12px; 9 | --color-text: #fff; 10 | --color-bg: #000; 11 | --color-link: #fff; 12 | --color-link-hover: #c471e1; 13 | --page-padding: 1.5rem; 14 | --color-card-1: #d09df2; 15 | --color-card-2: #9df2eb; 16 | --color-card-3: #f5e2a4; 17 | --color-card-4: #d09df2; 18 | --color-card-5: #9dcaf2; 19 | --color-card-6: #f29dcc; 20 | --color-bg-card: rgba(255, 255, 255, 0.2); 21 | --color-bg-card-inner: rgb(41 27 41); 22 | } 23 | 24 | body { 25 | margin: 0; 26 | color: var(--color-text); 27 | background-color: var(--color-bg); 28 | font-family: "Kode Mono", monospace; 29 | -webkit-font-smoothing: antialiased; 30 | -moz-osx-font-smoothing: grayscale; 31 | background-image: url(../img/noise.png), radial-gradient(circle, rgb(52 33 56) 0%, rgb(0 0 0) 100%); 32 | background-size: 400px, 100% 100vh; 33 | background-attachment: fixed; 34 | overflow-x: hidden; 35 | } 36 | 37 | /* Page Loader */ 38 | .js .loading::before, 39 | .js .loading::after { 40 | content: ''; 41 | position: fixed; 42 | z-index: 1000; 43 | } 44 | 45 | .js .loading::before { 46 | top: 0; 47 | left: 0; 48 | width: 100%; 49 | height: 100%; 50 | background: var(--color-bg); 51 | } 52 | 53 | .js .loading::after { 54 | top: 50%; 55 | left: 50%; 56 | width: 60px; 57 | height: 60px; 58 | margin: -30px 0 0 -30px; 59 | border-radius: 50%; 60 | opacity: 0.4; 61 | background: var(--color-link); 62 | animation: loaderAnim 0.7s linear infinite alternate forwards; 63 | 64 | } 65 | 66 | @keyframes loaderAnim { 67 | to { 68 | opacity: 1; 69 | transform: scale3d(0.5,0.5,1); 70 | } 71 | } 72 | 73 | a { 74 | text-decoration: underline; 75 | color: var(--color-link); 76 | outline: none; 77 | cursor: pointer; 78 | } 79 | 80 | a:hover { 81 | text-decoration: underline; 82 | color: var(--color-link-hover); 83 | outline: none; 84 | } 85 | 86 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 87 | a:focus { 88 | /* Provide a fallback style for browsers 89 | that don't support :focus-visible */ 90 | outline: none; 91 | background: lightgrey; 92 | } 93 | 94 | a:focus:not(:focus-visible) { 95 | /* Remove the focus indicator on mouse-focus for browsers 96 | that do support :focus-visible */ 97 | background: transparent; 98 | } 99 | 100 | a:focus-visible { 101 | /* Draw a very noticeable focus style for 102 | keyboard-focus on browsers that do support 103 | :focus-visible */ 104 | outline: 2px solid red; 105 | background: transparent; 106 | } 107 | 108 | .unbutton { 109 | background: none; 110 | border: 0; 111 | padding: 0; 112 | margin: 0; 113 | font: inherit; 114 | cursor: pointer; 115 | } 116 | 117 | .unbutton:focus { 118 | outline: none; 119 | } 120 | 121 | .frame { 122 | padding: var(--page-padding); 123 | position: relative; 124 | display: grid; 125 | z-index: 1000; 126 | width: 100%; 127 | height: 100%; 128 | grid-row-gap: 1rem; 129 | grid-column-gap: 2rem; 130 | pointer-events: none; 131 | justify-items: start; 132 | grid-template-columns: auto auto; 133 | grid-template-areas: 'title title' 'back archive' 'sponsor sponsor' 'hire hire'; 134 | } 135 | 136 | .frame a { 137 | pointer-events: auto; 138 | } 139 | 140 | .frame__title { 141 | grid-area: title; 142 | font-size: inherit; 143 | margin: 0; 144 | } 145 | 146 | .frame__back { 147 | grid-area: back; 148 | justify-self: start; 149 | } 150 | 151 | .frame__archive { 152 | grid-area: archive; 153 | justify-self: start; 154 | } 155 | 156 | .frame__sub { 157 | display: grid; 158 | position: fixed; 159 | bottom: var(--page-padding); 160 | right: var(--page-padding); 161 | width: 50px; 162 | height: 50px; 163 | border: 1px solid var(--color-link-hover); 164 | place-items: center; 165 | border-radius: 50%; 166 | } 167 | 168 | .frame__sub:hover::before, 169 | .frame__sub:focus::before { 170 | content: ''; 171 | position: absolute; 172 | width: 30px; 173 | height: 30px; 174 | top: -30%; 175 | left: -30%; 176 | } 177 | 178 | .frame__sub svg { 179 | fill: var(--color-link-hover); 180 | width: 25px; 181 | height: 25px; 182 | } 183 | 184 | .modal { 185 | pointer-events: none; 186 | opacity: 0; 187 | transform: translate3d(0,20px,0); 188 | position: absolute; 189 | bottom: 55px; 190 | right: 0px; 191 | background: #8a74c4; 192 | color: #fff; 193 | width: 280px; 194 | max-width: calc(100vw - var(--page-padding) * 2); 195 | line-height: 1.4; 196 | padding: 1.5rem; 197 | font-size: 16px; 198 | border-radius: 8px; 199 | transition: all 0.3s; 200 | } 201 | 202 | .frame__sub:hover .modal, 203 | .frame__sub:focus .modal { 204 | pointer-events: auto; 205 | opacity: 1; 206 | transform: translate3d(0px,0px,0px); 207 | } 208 | 209 | .frame__hire { 210 | grid-area: hire; 211 | max-width: 200px; 212 | } 213 | 214 | .frame__demos { 215 | grid-area: demos; 216 | display: flex; 217 | gap: 1rem; 218 | } 219 | 220 | main { 221 | position: relative; 222 | } 223 | 224 | .intro { 225 | width: 100%; 226 | display: grid; 227 | grid-template-columns: 100%; 228 | grid-template-rows: 20vh 20vh auto; 229 | grid-template-areas: 'intro-title' 'intro-hint' '...'; 230 | place-items: center; 231 | padding: 0 var(--page-padding); 232 | } 233 | 234 | .intro__title { 235 | text-transform: uppercase; 236 | font-size: clamp(2rem,7vw,8rem); 237 | font-weight: 400; 238 | grid-area: intro-title; 239 | position: relative; 240 | z-index: 100; 241 | align-self: center; 242 | margin: 0; 243 | text-align: center; 244 | } 245 | 246 | .intro__hint { 247 | grid-area: intro-hint; 248 | position: relative; 249 | z-index: 100; 250 | align-self: center; 251 | font-size: 1.5rem; 252 | text-align: center; 253 | } 254 | 255 | .intro__hint::after { 256 | content: '\00BB'; 257 | position: absolute; 258 | top: 100%; 259 | left: 0%; 260 | text-align: center; 261 | font-size: 3rem; 262 | width: 100%; 263 | transform: rotate(90deg); 264 | animation: pulse 0.3s linear alternate infinite; 265 | } 266 | 267 | @keyframes pulse { 268 | to { 269 | top: 120%; 270 | } 271 | } 272 | 273 | .outro { 274 | display: grid; 275 | place-items: center; 276 | margin: 40vh 0; 277 | } 278 | 279 | .outro__title { 280 | font-weight: 300; 281 | font-size: clamp(1.5rem,10vw,2rem); 282 | } 283 | 284 | .grid { 285 | position: relative; 286 | perspective: 1000px; 287 | align-self: start; 288 | grid-area: intro-title; 289 | grid-row: 1 / span 3; 290 | display: grid; 291 | grid-template-columns: repeat(3,auto); 292 | justify-content: center; 293 | gap: 3rem; 294 | filter: brightness(70%); 295 | } 296 | 297 | .card { 298 | width: 30vw; 299 | max-width: 255px; 300 | min-width: 150px; 301 | aspect-ratio: 2/3; 302 | font-size: 9px; 303 | text-transform: uppercase; 304 | padding: 5px; 305 | display: grid; 306 | grid-template-columns: 1fr 1fr; 307 | border-radius: 10px; 308 | position: relative; 309 | align-items: stretch; 310 | outline: 1px solid var(--color-card); 311 | background: var(--color-bg-card); 312 | grid-template-areas: 'card-img card-img' 'card-title card-meta' 'card-subtitle card-subtitle' 'card-desc card-desc'; 313 | } 314 | 315 | .grid .card { 316 | box-shadow: 0 2px 7px 0 rgba(0,0,0,0.8); 317 | } 318 | 319 | .card:nth-child(1n) { 320 | --color-card: var(--color-card-1); 321 | } 322 | 323 | .card:nth-child(2n) { 324 | --color-card: var(--color-card-2); 325 | } 326 | 327 | .card:nth-child(3n) { 328 | --color-card: var(--color-card-3); 329 | } 330 | 331 | .card:nth-child(4n) { 332 | --color-card: var(--color-card-4); 333 | } 334 | 335 | .card:nth-child(5n) { 336 | --color-card: var(--color-card-5); 337 | } 338 | 339 | .card:nth-child(6n) { 340 | --color-card: var(--color-card-6); 341 | } 342 | 343 | .card > * { 344 | background-color: var(--color-bg-card-inner); 345 | } 346 | 347 | .card__img { 348 | grid-area: card-img; 349 | background-size: cover; 350 | background-position: 50% 50%; 351 | aspect-ratio: 1; 352 | max-width: 100%; 353 | border-radius: 6px 6px 0 0; 354 | } 355 | 356 | .card__title { 357 | padding: 0.5rem 3px; 358 | grid-area: card-title; 359 | margin: 0; 360 | } 361 | 362 | .card__meta { 363 | grid-area: card-meta; 364 | padding: 0.5rem 3px; 365 | text-align: right; 366 | } 367 | 368 | .card__subtitle { 369 | grid-area: card-subtitle; 370 | margin: 0; 371 | padding: 0 3px; 372 | } 373 | 374 | .card__description { 375 | grid-area: card-desc; 376 | margin: 0; 377 | border-radius: 0 0 6px 6px; 378 | padding: 0 3px; 379 | } 380 | 381 | .card-wrap { 382 | margin-top: 5vh; 383 | display: grid; 384 | grid-gap: 2rem; 385 | grid-auto-flow: row; 386 | grid-template-columns: 250px; 387 | text-align: center; 388 | justify-items: center; 389 | } 390 | 391 | .card--rel { 392 | align-items: start; 393 | background: rgba(255,255,255,0.1); 394 | } 395 | 396 | .card--rel .card__img { 397 | aspect-ratio: 4 / 3; 398 | filter: contrast(0.8); 399 | } 400 | 401 | .card--rel .card__title { 402 | grid-column-end: 3; 403 | background: none; 404 | font-size: 1.5rem; 405 | font-weight: 400; 406 | text-transform: none; 407 | padding: 2rem 1rem 1rem; 408 | } 409 | 410 | .credits { 411 | font-size: 1.5rem; 412 | text-align: center; 413 | margin: 50vh auto 0; 414 | padding-bottom: 50vh; 415 | } 416 | 417 | .section-title { 418 | width: 100%; 419 | display: grid; 420 | place-items: center; 421 | font-size: clamp(2rem,6vw,6rem); 422 | line-height: 1; 423 | font-weight: 400; 424 | margin: 25vh auto 0; 425 | max-width: 600px; 426 | text-align: center; 427 | text-transform: uppercase; 428 | } 429 | 430 | .wrap { 431 | position: relative; 432 | min-height: 100vh; 433 | } 434 | 435 | .wrap__inner { 436 | position: relative; 437 | perspective: 1000px; 438 | } 439 | 440 | .content { 441 | width: 100vw; 442 | position: relative; 443 | transform-style: preserve-3d; 444 | display: grid; 445 | grid-template-areas: 'card'; 446 | grid-template-columns: 100%; 447 | place-items: center; 448 | } 449 | 450 | .content .card { 451 | grid-area: card; 452 | background: rgba(132, 128, 143, 0.36); 453 | } 454 | 455 | @media screen and (min-width: 53em) { 456 | body { 457 | --page-padding: 2rem; 458 | } 459 | .frame { 460 | position: fixed; 461 | top: 0; 462 | left: 0; 463 | width: 100%; 464 | height: 100%; 465 | grid-template-columns: auto auto auto 1fr; 466 | grid-template-rows: auto auto; 467 | align-content: space-between; 468 | grid-template-areas: 'title back archive sponsor' 'hire ... ... sub'; 469 | } 470 | .frame__sub { 471 | justify-self: end; 472 | } 473 | .frame__title { 474 | padding-right: 4rem; 475 | } 476 | .frame__hire { 477 | align-self: end; 478 | } 479 | .modal { 480 | bottom: 50px; 481 | right: 50px; 482 | } 483 | .intro { 484 | grid-template-rows: 60vh 40vh auto; 485 | } 486 | .intro__title { 487 | align-self: end; 488 | } 489 | .grid { 490 | padding-top: 12vh; 491 | } 492 | .content { 493 | min-height: 100vh; 494 | justify-content: center; 495 | align-items: center; 496 | } 497 | .card-wrap { 498 | grid-template-columns: repeat(2, 300px); 499 | } 500 | } 501 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/favicon.ico -------------------------------------------------------------------------------- /img/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/.DS_Store -------------------------------------------------------------------------------- /img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/1.jpg -------------------------------------------------------------------------------- /img/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/10.jpg -------------------------------------------------------------------------------- /img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/2.jpg -------------------------------------------------------------------------------- /img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/3.jpg -------------------------------------------------------------------------------- /img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/4.jpg -------------------------------------------------------------------------------- /img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/5.jpg -------------------------------------------------------------------------------- /img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/6.jpg -------------------------------------------------------------------------------- /img/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/7.jpg -------------------------------------------------------------------------------- /img/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/8.jpg -------------------------------------------------------------------------------- /img/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/9.jpg -------------------------------------------------------------------------------- /img/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/img/noise.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 3D Stack Motion Effect | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 |
21 |
22 |

#3D #stack Motion Effect on #Scroll
inspired by Looksrare: NFT cards

23 | Article 24 | All demos 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 |
Want magic like this on your website? Hire us
35 |
36 |
37 |

The Next Evolution

38 |

Scroll into the future

39 |
40 |
41 |
42 |

AI Horizons

43 |

Beyond Human Limits

44 | V1.0 45 |

Explore the future where AI transforms imagination into reality.

46 |
47 |
48 |
49 |

Tech Odyssey

50 |

Unveiling Tomorrow

51 | V2.0 52 |

Embark on a journey into the realm of cutting-edge technology reshaping our world.

53 |
54 |
55 |
56 |

Digital Frontiers

57 |

Pushing Boundaries

58 | V3.0 59 |

Enter the realm where innovation meets possibility, shaping the future of humanity.

60 |
61 |
62 |
63 |

AI Nexus

64 |

Bridging Realms

65 | V4.0 66 |

Dive into the interconnected world of AI, where algorithms shape the future of human experience.

67 |
68 |
69 |
70 |

AI Innovate

71 |

Pioneering Tomorrow

72 | V5.0 73 |

Join the forefront of AI innovation, where creativity meets computational intelligence to shape a better future.

74 |
75 |
76 |
77 |

AI Horizons

78 |

Beyond Human Limits

79 | V6.0 80 |

Explore the future where AI transforms imagination into reality.

81 |
82 |
83 |
84 |

AI Frontier

85 |

Exploring New Horizons

86 | V7.0 87 |

Venture into uncharted territories where AI blazes trails towards unprecedented possibilities.

88 |
89 |
90 |
91 |

AI Visionary

92 |

Envisioning Tomorrow

93 | V8.0 94 |

Embrace the visionary realm of AI, where dreams of the future become the reality of today.

95 |
96 |
97 |
98 |

AI Odyssey

99 |

Journey to Tomorrow

100 | V9.0 101 |

Embark on an epic odyssey through the realms of AI, where innovation knows no bounds.

102 |
103 |
104 |
105 |

A New Frontier

106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |

Chronicles of Circuitry

194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |

Synthetica Sapiens

282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |

More you might like

371 |
372 | 378 |
379 | 382 |

383 | On-Scroll Column & Row Animations 384 |

385 |
386 |
387 |
388 |

Made by @codrops

389 |
390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | -------------------------------------------------------------------------------- /js/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/3DStackMotion/75cbda91ed26d31aeeb5a5b9887848e5a7005c7f/js/.DS_Store -------------------------------------------------------------------------------- /js/ScrollTrigger.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * ScrollTrigger 3.12.5 3 | * https://gsap.com 4 | * 5 | * @license Copyright 2024, GreenSock. All rights reserved. 6 | * Subject to the terms at https://gsap.com/standard-license or for Club GSAP members, the agreement issued with that membership. 7 | * @author: Jack Doyle, jack@greensock.com 8 | */ 9 | 10 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).window=e.window||{})}(this,function(e){"use strict";function _defineProperties(e,t){for(var r=0;r=Math.abs(r)?t:r}function O(){(Ae=Ce.core.globals().ScrollTrigger)&&Ae.core&&function _integrate(){var e=Ae.core,r=e.bridge||{},t=e._scrollers,n=e._proxies;t.push.apply(t,Ie),n.push.apply(n,Le),Ie=t,Le=n,i=function _bridge(e,t){return r[e](t)}}()}function P(e){return Ce=e||r(),!Te&&Ce&&"undefined"!=typeof document&&document.body&&(Se=window,Pe=(ke=document).documentElement,Me=ke.body,t=[Se,ke,Pe,Me],Ce.utils.clamp,Be=Ce.core.context||function(){},Oe="onpointerenter"in Me?"pointer":"mouse",Ee=k.isTouch=Se.matchMedia&&Se.matchMedia("(hover: none), (pointer: coarse)").matches?1:"ontouchstart"in Se||0=o,n=Math.abs(t)>=o;S&&(r||n)&&S(se,e,t,me,ye),r&&(m&&0Math.abs(t)?"x":"y",ie=!0),"y"!==ae&&(me[2]+=e,se._vx.update(e,!0)),"x"!==ae&&(ye[2]+=t,se._vy.update(t,!0)),n?ee=ee||requestAnimationFrame(ff):ff()}function jf(e){if(!df(e,1)){var t=(e=M(e,s)).clientX,r=e.clientY,n=t-se.x,o=r-se.y,i=se.isDragging;se.x=t,se.y=r,(i||Math.abs(se.startX-t)>=a||Math.abs(se.startY-r)>=a)&&(h&&(re=!0),i||(se.isDragging=!0),hf(n,o),i||p&&p(se))}}function mf(e){return e.touches&&1=e)return a[n];return a[n-1]}for(n=a.length,e+=r;n--;)if(a[n]<=e)return a[n];return a[0]}:function(e,t,r){void 0===r&&(r=.001);var n=i(e);return!t||Math.abs(n-e)r&&(n*=t/100),e=e.substr(0,r-1)),e=n+(e in H?H[e]*t:~e.indexOf("%")?parseFloat(e)*t/100:parseFloat(e)||0)}return e}function Db(e,t,r,n,o,i,a,s){var l=o.startColor,c=o.endColor,u=o.fontSize,f=o.indent,d=o.fontWeight,p=Xe.createElement("div"),g=La(r)||"fixed"===z(r,"pinType"),h=-1!==e.indexOf("scroller"),v=g?We:r,b=-1!==e.indexOf("start"),m=b?l:c,y="border-color:"+m+";font-size:"+u+";color:"+m+";font-weight:"+d+";pointer-events:none;white-space:nowrap;font-family:sans-serif,Arial;z-index:1000;padding:4px 8px;border-width:0;border-style:solid;";return y+="position:"+((h||s)&&g?"fixed;":"absolute;"),!h&&!s&&g||(y+=(n===Fe?q:I)+":"+(i+parseFloat(f))+"px;"),a&&(y+="box-sizing:border-box;text-align:left;width:"+a.offsetWidth+"px;"),p._isStart=b,p.setAttribute("class","gsap-marker-"+e+(t?" marker-"+t:"")),p.style.cssText=y,p.innerText=t||0===t?e+"-"+t:e,v.children[0]?v.insertBefore(p,v.children[0]):v.appendChild(p),p._offset=p["offset"+n.op.d2],X(p,0,n,b),p}function Ib(){return 34We.clientWidth)||(Ie.cache++,v?D=D||requestAnimationFrame(Z):Z(),st||U("scrollStart"),st=at())}function Kb(){y=Ne.innerWidth,m=Ne.innerHeight}function Lb(){Ie.cache++,je||h||Xe.fullscreenElement||Xe.webkitFullscreenElement||b&&y===Ne.innerWidth&&!(Math.abs(Ne.innerHeight-m)>.25*Ne.innerHeight)||c.restart(!0)}function Ob(){return xb(ne,"scrollEnd",Ob)||Pt(!0)}function Rb(e){for(var t=0;tt,n=e._startClamp&&e.start>=t;(r||n)&&e.setPositions(n?t-1:e.start,r?Math.max(n?t:e.start+1,t):e.end,!0)}),Zb(!1),et=0,r.forEach(function(e){return e&&e.render&&e.render(-1)}),Ie.forEach(function(e){Ta(e)&&(e.smooth&&requestAnimationFrame(function(){return e.target.style.scrollBehavior="smooth"}),e.rec&&e(e.rec))}),Tb(w,1),c.pause(),kt++,Z(rt=2),Tt.forEach(function(e){return Ta(e.vars.onRefresh)&&e.vars.onRefresh(e)}),rt=ne.isRefreshing=!1,U("refresh")}else wb(ne,"scrollEnd",Ob)},Q=0,Mt=1,Z=function _updateAll(e){if(2===e||!rt&&!S){ne.isUpdating=!0,ot&&ot.update(0);var t=Tt.length,r=at(),n=50<=r-R,o=t&&Tt[0].scroll();if(Mt=o=Qa(be,he)){if(ie&&Ae()&&!de)for(i=ie.parentNode;i&&i!==We;)i._pinOffset&&(B-=i._pinOffset,q-=i._pinOffset),i=i.parentNode}else o=mb(ae),s=he===Fe,a=Ae(),G=parseFloat(j(he.a))+_,!y&&1=q})},Te.update=function(e,t,r){if(!de||r||e){var n,o,i,a,s,l,c,u=!0===rt?re:Te.scroll(),f=e?0:(u-B)/N,d=f<0?0:1u+(u-R)/(at()-Ke)*M&&(d=.9999)),d!==p&&Te.enabled){if(a=(s=(n=Te.isActive=!!d&&d<1)!=(!!p&&p<1))||!!d!=!!p,Te.direction=p=Qa(be,he),fe)if(e||!n&&!l)oc(ae,U);else{var g=wt(ae,!0),h=u-B;oc(ae,We,g.top+(he===Fe?h:0)+xt,g.left+(he===Fe?0:h)+xt)}Et(n||l?W:V),$&&d<1&&n||b(G+(1!==d||l?0:Q))}}else b(Ia(G+Q*d));!ue||A.tween||je||it||te.restart(!0),S&&(s||ce&&d&&(d<1||!tt))&&Ve(S.targets).forEach(function(e){return e.classList[n||ce?"add":"remove"](S.className)}),!T||ve||e||T(Te),a&&!je?(ve&&(c&&("complete"===i?O.pause().totalProgress(1):"reset"===i?O.restart(!0).pause():"restart"===i?O.restart(!0):O[i]()),T&&T(Te)),!s&&tt||(k&&s&&Xa(Te,k),xe[o]&&Xa(Te,xe[o]),ce&&(1===d?Te.kill(!1,1):xe[o]=0),s||xe[o=1===d?1:3]&&Xa(Te,xe[o])),pe&&!n&&Math.abs(Te.getVelocity())>(Ua(pe)?pe:2500)&&(Wa(Te.callbackAnimation),ee?ee.progress(1):Wa(O,"reverse"===i?1:!d,1))):ve&&T&&!je&&T(Te)}if(x){var v=de?u/de.duration()*(de._caScrollDist||0):u;y(v+(Y._isFlipped?1:0)),x(v)}C&&C(-u/de.duration()*(de._caScrollDist||0))}},Te.enable=function(e,t){Te.enabled||(Te.enabled=!0,wb(be,"resize",Lb),me||wb(be,"scroll",Jb),Se&&wb(ScrollTrigger,"refreshInit",Se),!1!==e&&(Te.progress=Oe=0,D=R=Me=Ae()),!1!==t&&Te.refresh())},Te.getTween=function(e){return e&&A?A.tween:ee},Te.setPositions=function(e,t,r,n){if(de){var o=de.scrollTrigger,i=de.duration(),a=o.end-o.start;e=o.start+a*e/i,t=o.start+a*t/i}Te.refresh(!1,!1,{start:Da(e,r&&!!Te._startClamp),end:Da(t,r&&!!Te._endClamp)},n),Te.update()},Te.adjustPinSpacing=function(e){if(Z&&e){var t=Z.indexOf(he.d)+1;Z[t]=parseFloat(Z[t])+e+xt,Z[1]=parseFloat(Z[1])+e+xt,Et(Z)}},Te.disable=function(e,t){if(Te.enabled&&(!1!==e&&Te.revert(!0,!0),Te.enabled=Te.isActive=!1,t||ee&&ee.pause(),re=0,n&&(n.uncache=1),Se&&xb(ScrollTrigger,"refreshInit",Se),te&&(te.pause(),A.tween&&A.tween.kill()&&(A.tween=0)),!me)){for(var r=Tt.length;r--;)if(Tt[r].scroller===be&&Tt[r]!==Te)return;xb(be,"resize",Lb),me||xb(be,"scroll",Jb)}},Te.kill=function(e,t){Te.disable(e,t),ee&&!t&&ee.kill(),a&&delete St[a];var r=Tt.indexOf(Te);0<=r&&Tt.splice(r,1),r===Qe&&0i&&(b()>i?a.progress(1)&&b(i):a.resetTo("scrollY",i))}Va(e)||(e={}),e.preventDefault=e.isNormalizer=e.allowClicks=!0,e.type||(e.type="wheel,touch"),e.debounce=!!e.debounce,e.id=e.id||"normalizer";var n,i,l,o,a,c,u,s,f=e.normalizeScrollX,t=e.momentum,r=e.allowNestedScroll,d=e.onRelease,p=J(e.target)||Je,g=He.core.globals().ScrollSmoother,h=g&&g.get(),v=E&&(e.content&&J(e.content)||h&&!1!==e.content&&!h.smooth()&&h.content()),b=K(p,Fe),m=K(p,Ye),y=1,x=(k.isTouch&&Ne.visualViewport?Ne.visualViewport.scale*Ne.visualViewport.width:Ne.outerWidth)/Ne.innerWidth,w=0,_=Ta(t)?function(){return t(n)}:function(){return t||2.8},C=xc(p,e.type,!0,r),T=Ha,S=Ha;return v&&He.set(v,{y:"+=0"}),e.ignoreCheck=function(e){return E&&"touchmove"===e.type&&function ignoreDrag(){if(o){requestAnimationFrame(zq);var e=Ia(n.deltaY/2),t=S(b.v-e);if(v&&t!==b.v+b.offset){b.offset=t-b.v;var r=Ia((parseFloat(v&&v._gsap.y)||0)-b.offset);v.style.transform="matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, "+r+", 0, 1)",v._gsap.y=r+"px",b.cacheID=Ie.cache,Z()}return!0}b.offset&&Dq(),o=!0}()||1.05=i||i-1<=r)&&He.to({},{onUpdate:Jq,duration:o})}else s.restart(!0);d&&d(e)},e.onWheel=function(){a._ts&&a.pause(),1e3 { 29 | winsize = { width: window.innerWidth, height: window.innerHeight }; 30 | this.scroll(); 31 | }, 100); 32 | window.addEventListener('resize', throttledResize); 33 | } 34 | 35 | // Defines the scroll effect logic for the stack. 36 | scroll() { 37 | // Initially hides the content element and prepares it for the animation by setting its transform property. 38 | // This sets the initial 3D rotation of the stack and its cards, defining their starting visual appearance. 39 | this.contentElement.style.transform = 'rotate3d(1, 0, 0, -25deg) rotate3d(0, 1, 0, 50deg) rotate3d(0, 0, 1, 25deg)'; 40 | this.contentElement.style.opacity = 0; 41 | 42 | // Clears previous timeline if exists to prevent conflicts. 43 | if (this.tl) { 44 | this.tl.kill(); 45 | } 46 | 47 | // Creates a new timeline for the scroll-triggered animation. 48 | this.tl = gsap.timeline({ 49 | defaults: { 50 | ease: 'power1', 51 | }, 52 | scrollTrigger: { 53 | trigger: this.wrapElement, 54 | start: 'top center', 55 | end: '+=150%', 56 | scrub: true, 57 | // Sets opacity to 1 when the element comes into view. 58 | onEnter: () => gsap.set(this.contentElement, {opacity: 1}), 59 | onEnterBack: () => gsap.set(this.contentElement, {opacity: 1}), 60 | // Hides the element when it leaves the view. 61 | onLeave: () => gsap.set(this.contentElement, {opacity: 0}), 62 | onLeaveBack: () => gsap.set(this.contentElement, {opacity: 0}) 63 | }, 64 | }) 65 | .fromTo(this.imageElements, { 66 | // Animates from a starting z position based on the window size. 67 | z: (pos) => -2.65 * winsize.width - pos * 0.03 * winsize.width, 68 | }, { 69 | // Animates to an ending z position, creating a 3D effect as elements scroll. 70 | z: (pos) => 1.4 * winsize.width + (this.imagesTotal - pos - 1) * 0.03 * winsize.width, 71 | }, 0) 72 | .fromTo(this.imageElements, { 73 | rotationZ: -220, 74 | }, { 75 | rotationY: -30, 76 | rotationZ: 120, 77 | // Stagger effect for individual elements to animate sequentially. 78 | stagger: 0.005, 79 | }, 0) 80 | /*.fromTo(this.imageElements, { 81 | filter: 'brightness(20%)', 82 | }, { 83 | filter: 'brightness(150%)', 84 | stagger: 0.005, 85 | }, 0);*/ 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /js/effect-2/stackMotionEffect.js: -------------------------------------------------------------------------------- 1 | import { throttle } from '../utils.js'; 2 | 3 | let winsize = {width: window.innerWidth, height: window.innerHeight}; 4 | 5 | export class StackMotionEffect { 6 | constructor(stackEl) { 7 | // Check if the provided element is valid. 8 | if (!stackEl || !(stackEl instanceof HTMLElement)) { 9 | throw new Error('Invalid element provided.'); 10 | } 11 | 12 | this.wrapElement = stackEl; 13 | this.contentElement = this.wrapElement.querySelector('.content'); 14 | this.imageElements = [this.contentElement.querySelectorAll('.card')]; 15 | this.imagesTotal = this.imageElements.length; 16 | 17 | // Set up the effect for the provided element. 18 | this.initializeEffect(stackEl); 19 | } 20 | 21 | // Sets up the initial effect on the provided element. 22 | initializeEffect(element) { 23 | // Scroll effect. 24 | this.scroll(); 25 | 26 | const throttledResize = throttle(() => { 27 | winsize = { width: window.innerWidth, height: window.innerHeight }; 28 | this.scroll(); 29 | }, 100); 30 | window.addEventListener('resize', throttledResize); 31 | } 32 | 33 | scroll() { 34 | // Let's set the initial rotation for the content element 35 | this.contentElement.style.transform = 'rotate3d(1, 0, 0, 55deg) rotate3d(0, 1, 0, 30deg)'; 36 | this.contentElement.style.opacity = 0; 37 | 38 | if (this.tl) { 39 | this.tl.kill(); 40 | } 41 | 42 | this.tl = gsap.timeline({ 43 | defaults: { 44 | ease: 'sine.inOut', 45 | }, 46 | scrollTrigger: { 47 | trigger: this.wrapElement, 48 | start: 'top center', 49 | end: '+=150%', 50 | scrub: true, 51 | onEnter: () => gsap.set(this.contentElement, {opacity: 1}), 52 | onEnterBack: () => gsap.set(this.contentElement, {opacity: 1}), 53 | onLeave: () => gsap.set(this.contentElement, {opacity: 0}), 54 | onLeaveBack: () => gsap.set(this.contentElement, {opacity: 0}), 55 | }, 56 | }) 57 | .fromTo(this.imageElements, { 58 | z: (pos) => -1.2 * winsize.height - pos * 0.08 * winsize.height, 59 | }, { 60 | z: (pos) => 3 * winsize.height + (this.imagesTotal - pos - 1) * 0.08 * winsize.height, 61 | }, 0) 62 | .fromTo(this.imageElements, { 63 | rotationZ: -130, 64 | }, { 65 | rotationZ: 360, 66 | stagger: 0.006, 67 | }, 0) 68 | /*.fromTo(this.imageElements, { 69 | filter: 'brightness(10%)', 70 | }, { 71 | filter: 'brightness(400%)', 72 | stagger: 0.005, 73 | }, 0);*/ 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /js/effect-3/stackMotionEffect.js: -------------------------------------------------------------------------------- 1 | import { throttle } from '../utils.js'; 2 | 3 | let winsize = {width: window.innerWidth, height: window.innerHeight}; 4 | 5 | export class StackMotionEffect { 6 | constructor(stackEl) { 7 | // Check if the provided element is valid. 8 | if (!stackEl || !(stackEl instanceof HTMLElement)) { 9 | throw new Error('Invalid element provided.'); 10 | } 11 | 12 | this.wrapElement = stackEl; 13 | this.contentElement = this.wrapElement.querySelector('.content'); 14 | this.imageElements = [this.contentElement.querySelectorAll('.card')]; 15 | this.imagesTotal = this.imageElements.length; 16 | 17 | // Set up the effect for the provided element. 18 | this.initializeEffect(stackEl); 19 | } 20 | 21 | // Sets up the initial effect on the provided element. 22 | initializeEffect(element) { 23 | // Scroll effect. 24 | this.scroll(); 25 | 26 | const throttledResize = throttle(() => { 27 | winsize = { width: window.innerWidth, height: window.innerHeight }; 28 | this.scroll(); 29 | }, 100); 30 | window.addEventListener('resize', throttledResize); 31 | } 32 | 33 | scroll() { 34 | // Let's set the initial rotation for the content element 35 | this.contentElement.style.transform = 'rotate3d(1, 0, 0, 25deg) rotate3d(0, 1, 0, -50deg) rotate3d(0, 0, 1, 25deg)'; 36 | this.contentElement.style.opacity = 0; 37 | 38 | if (this.tl) { 39 | this.tl.kill(); 40 | } 41 | 42 | this.tl = gsap.timeline({ 43 | defaults: { 44 | ease: 'power1', 45 | }, 46 | scrollTrigger: { 47 | trigger: this.wrapElement, 48 | start: 'top center', 49 | end: '+=150%', 50 | scrub: true, 51 | onEnter: () => gsap.set(this.contentElement, {opacity: 1}), 52 | onEnterBack: () => gsap.set(this.contentElement, {opacity: 1}), 53 | onLeave: () => gsap.set(this.contentElement, {opacity: 0}), 54 | onLeaveBack: () => gsap.set(this.contentElement, {opacity: 0}), 55 | }, 56 | }) 57 | .fromTo(this.imageElements, { 58 | z: (pos) => -2.5 * winsize.width/2 - pos * 0.07 * winsize.width, 59 | }, { 60 | z: (pos) => 2.5 * winsize.width + (this.imagesTotal - pos - 1) * 0.07 * winsize.width, 61 | }, 0) 62 | .fromTo(this.imageElements, { 63 | rotationZ: 10, 64 | }, { 65 | rotationX: 20, 66 | rotationZ: 280, 67 | yPercent: -100, 68 | stagger: 0.005, 69 | }, 0) 70 | /*.fromTo(this.imageElements, { 71 | filter: 'brightness(20%)', 72 | }, { 73 | filter: 'brightness(350%)', 74 | stagger: 0.005, 75 | }, 0);*/ 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /js/gsap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * GSAP 3.12.5 3 | * https://gsap.com 4 | * 5 | * @license Copyright 2024, GreenSock. All rights reserved. 6 | * Subject to the terms at https://gsap.com/standard-license or for Club GSAP members, the agreement issued with that membership. 7 | * @author: Jack Doyle, jack@greensock.com 8 | */ 9 | 10 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).window=t.window||{})}(this,function(e){"use strict";function _inheritsLoose(t,e){t.prototype=Object.create(e.prototype),(t.prototype.constructor=t).__proto__=e}function _assertThisInitialized(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function r(t){return"string"==typeof t}function s(t){return"function"==typeof t}function t(t){return"number"==typeof t}function u(t){return void 0===t}function v(t){return"object"==typeof t}function w(t){return!1!==t}function x(){return"undefined"!=typeof window}function y(t){return s(t)||r(t)}function P(t){return(i=yt(t,ot))&&ze}function Q(t,e){return console.warn("Invalid property",t,"set to",e,"Missing plugin? gsap.registerPlugin()")}function R(t,e){return!e&&console.warn(t)}function S(t,e){return t&&(ot[t]=e)&&i&&(i[t]=e)||ot}function T(){return 0}function ea(t){var e,r,i=t[0];if(v(i)||s(i)||(t=[t]),!(e=(i._gsap||{}).harness)){for(r=gt.length;r--&&!gt[r].targetTest(i););e=gt[r]}for(r=t.length;r--;)t[r]&&(t[r]._gsap||(t[r]._gsap=new Vt(t[r],e)))||t.splice(r,1);return t}function fa(t){return t._gsap||ea(Mt(t))[0]._gsap}function ga(t,e,r){return(r=t[e])&&s(r)?t[e]():u(r)&&t.getAttribute&&t.getAttribute(e)||r}function ha(t,e){return(t=t.split(",")).forEach(e)||t}function ia(t){return Math.round(1e5*t)/1e5||0}function ja(t){return Math.round(1e7*t)/1e7||0}function ka(t,e){var r=e.charAt(0),i=parseFloat(e.substr(2));return t=parseFloat(t),"+"===r?t+i:"-"===r?t-i:"*"===r?t*i:t/i}function la(t,e){for(var r=e.length,i=0;t.indexOf(e[i])<0&&++ia;)s=s._prev;return s?(e._next=s._next,s._next=e):(e._next=t[r],t[r]=e),e._next?e._next._prev=e:t[i]=e,e._prev=s,e.parent=e._dp=t,e}function ya(t,e,r,i){void 0===r&&(r="_first"),void 0===i&&(i="_last");var n=e._prev,a=e._next;n?n._next=a:t[r]===e&&(t[r]=a),a?a._prev=n:t[i]===e&&(t[i]=n),e._next=e._prev=e.parent=null}function za(t,e){t.parent&&(!e||t.parent.autoRemoveChildren)&&t.parent.remove&&t.parent.remove(t),t._act=0}function Aa(t,e){if(t&&(!e||e._end>t._dur||e._start<0))for(var r=t;r;)r._dirty=1,r=r.parent;return t}function Ca(t,e,r,i){return t._startAt&&(L?t._startAt.revert(ht):t.vars.immediateRender&&!t.vars.autoRevert||t._startAt.render(e,!0,i))}function Ea(t){return t._repeat?Tt(t._tTime,t=t.duration()+t._rDelay)*t:0}function Ga(t,e){return(t-e._start)*e._ts+(0<=e._ts?0:e._dirty?e.totalDuration():e._tDur)}function Ha(t){return t._end=ja(t._start+(t._tDur/Math.abs(t._ts||t._rts||X)||0))}function Ia(t,e){var r=t._dp;return r&&r.smoothChildTiming&&t._ts&&(t._start=ja(r._time-(0X)&&e.render(r,!0)),Aa(t,e)._dp&&t._initted&&t._time>=t._dur&&t._ts){if(t._dur(n=Math.abs(n))&&(a=i,o=n);return a}function tb(t){return za(t),t.scrollTrigger&&t.scrollTrigger.kill(!!L),t.progress()<1&&Ct(t,"onInterrupt"),t}function wb(t){if(t)if(t=!t.name&&t.default||t,x()||t.headless){var e=t.name,r=s(t),i=e&&!r&&t.init?function(){this._props=[]}:t,n={init:T,render:he,add:Wt,kill:ce,modifier:fe,rawVars:0},a={targetTest:0,get:0,getSetter:ne,aliases:{},register:0};if(Ft(),t!==i){if(pt[e])return;qa(i,qa(ua(t,n),a)),yt(i.prototype,yt(n,ua(t,a))),pt[i.prop=e]=i,t.targetTest&&(gt.push(i),ft[e]=1),e=("css"===e?"CSS":e.charAt(0).toUpperCase()+e.substr(1))+"Plugin"}S(e,i),t.register&&t.register(ze,i,_e)}else At.push(t)}function zb(t,e,r){return(6*(t+=t<0?1:1>16,e>>8&St,e&St]:0:zt.black;if(!p){if(","===e.substr(-1)&&(e=e.substr(0,e.length-1)),zt[e])p=zt[e];else if("#"===e.charAt(0)){if(e.length<6&&(e="#"+(n=e.charAt(1))+n+(a=e.charAt(2))+a+(s=e.charAt(3))+s+(5===e.length?e.charAt(4)+e.charAt(4):"")),9===e.length)return[(p=parseInt(e.substr(1,6),16))>>16,p>>8&St,p&St,parseInt(e.substr(7),16)/255];p=[(e=parseInt(e.substr(1),16))>>16,e>>8&St,e&St]}else if("hsl"===e.substr(0,3))if(p=c=e.match(tt),r){if(~e.indexOf("="))return p=e.match(et),i&&p.length<4&&(p[3]=1),p}else o=+p[0]%360/360,u=p[1]/100,n=2*(h=p[2]/100)-(a=h<=.5?h*(u+1):h+u-h*u),3=U?u.endTime(!1):t._dur;return r(e)&&(isNaN(e)||e in o)?(a=e.charAt(0),s="%"===e.substr(-1),n=e.indexOf("="),"<"===a||">"===a?(0<=n&&(e=e.replace(/=/,"")),("<"===a?u._start:u.endTime(0<=u._repeat))+(parseFloat(e.substr(1))||0)*(s?(n<0?u:i).totalDuration()/100:1)):n<0?(e in o||(o[e]=h),o[e]):(a=parseFloat(e.charAt(n-1)+e.substr(n+1)),s&&i&&(a=a/100*(Z(i)?i[0]:i).totalDuration()),1=r&&te)return i;i=i._next}else for(i=t._last;i&&i._start>=r;){if("isPause"===i.data&&i._start=n._start)&&n._ts&&h!==n){if(n.parent!==this)return this.render(t,e,r);if(n.render(0=this.totalDuration()||!v&&_)&&(f!==this._start&&Math.abs(l)===Math.abs(this._ts)||this._lock||(!t&&g||!(v===m&&0=i&&(a instanceof $t?e&&n.push(a):(r&&n.push(a),t&&n.push.apply(n,a.getChildren(!0,e,r)))),a=a._next;return n},e.getById=function getById(t){for(var e=this.getChildren(1,1,1),r=e.length;r--;)if(e[r].vars.id===t)return e[r]},e.remove=function remove(t){return r(t)?this.removeLabel(t):s(t)?this.killTweensOf(t):(ya(this,t),t===this._recent&&(this._recent=this._last),Aa(this))},e.totalTime=function totalTime(t,e){return arguments.length?(this._forcing=1,!this._dp&&this._ts&&(this._start=ja(Rt.time-(0r:!r||s.isActive())&&n.push(s):(i=s.getTweensOf(a,r)).length&&n.push.apply(n,i),s=s._next;return n},e.tweenTo=function tweenTo(t,e){e=e||{};var r,i=this,n=xt(i,t),a=e.startAt,s=e.onStart,o=e.onStartParams,u=e.immediateRender,h=$t.to(i,qa({ease:e.ease||"none",lazy:!1,immediateRender:!1,time:n,overwrite:"auto",duration:e.duration||Math.abs((n-(a&&"time"in a?a.time:i._time))/i.timeScale())||X,onStart:function onStart(){if(i.pause(),!r){var t=e.duration||Math.abs((n-(a&&"time"in a?a.time:i._time))/i.timeScale());h._dur!==t&&Ra(h,t,0,1).render(h._time,!0,!0),r=1}s&&s.apply(h,o||[])}},e));return u?h.render(0):h},e.tweenFromTo=function tweenFromTo(t,e,r){return this.tweenTo(e,qa({startAt:{time:xt(this,t)}},r))},e.recent=function recent(){return this._recent},e.nextLabel=function nextLabel(t){return void 0===t&&(t=this._time),rb(this,xt(this,t))},e.previousLabel=function previousLabel(t){return void 0===t&&(t=this._time),rb(this,xt(this,t),1)},e.currentLabel=function currentLabel(t){return arguments.length?this.seek(t,!0):this.previousLabel(this._time+X)},e.shiftChildren=function shiftChildren(t,e,r){void 0===r&&(r=0);for(var i,n=this._first,a=this.labels;n;)n._start>=r&&(n._start+=t,n._end+=t),n=n._next;if(e)for(i in a)a[i]>=r&&(a[i]+=t);return Aa(this)},e.invalidate=function invalidate(t){var e=this._first;for(this._lock=0;e;)e.invalidate(t),e=e._next;return i.prototype.invalidate.call(this,t)},e.clear=function clear(t){void 0===t&&(t=!0);for(var e,r=this._first;r;)e=r._next,this.remove(r),r=e;return this._dp&&(this._time=this._tTime=this._pTime=0),t&&(this.labels={}),Aa(this)},e.totalDuration=function totalDuration(t){var e,r,i,n=0,a=this,s=a._last,o=U;if(arguments.length)return a.timeScale((a._repeat<0?a.duration():a.totalDuration())/(a.reversed()?-t:t));if(a._dirty){for(i=a.parent;s;)e=s._prev,s._dirty&&s.totalDuration(),o<(r=s._start)&&a._sort&&s._ts&&!a._lock?(a._lock=1,Ka(a,s,r-s._delay,1)._lock=0):o=r,r<0&&s._ts&&(n-=r,(!i&&!a._dp||i&&i.smoothChildTiming)&&(a._start+=r/a._ts,a._time-=r,a._tTime-=r),a.shiftChildren(-r,!1,-Infinity),o=0),s._end>n&&s._ts&&(n=s._end),s=e;Ra(a,a===I&&a._time>n?a._time:n,1,1),a._dirty=0}return a._tDur},Timeline.updateRoot=function updateRoot(t){if(I._ts&&(na(I,Ga(t,I)),f=Rt.frame),Rt.frame>=mt){mt+=q.autoSleep||120;var e=I._first;if((!e||!e._ts)&&q.autoSleep&&Rt._listeners.length<2){for(;e&&!e._ts;)e=e._next;e||Rt.sleep()}}},Timeline}(Ut);qa(Xt.prototype,{_lock:0,_hasPause:0,_forcing:0});function ac(t,e,i,n,a,o){var u,h,l,f;if(pt[t]&&!1!==(u=new pt[t]).init(a,u.rawVars?e[t]:function _processVars(t,e,i,n,a){if(s(t)&&(t=Kt(t,a,e,i,n)),!v(t)||t.style&&t.nodeType||Z(t)||$(t))return r(t)?Kt(t,a,e,i,n):t;var o,u={};for(o in t)u[o]=Kt(t[o],a,e,i,n);return u}(e[t],n,a,o,i),i,n,o)&&(i._pt=h=new _e(i._pt,a,t,0,1,u.render,u,0,u.priority),i!==d))for(l=i._ptLookup[i._targets.indexOf(a)],f=u._props.length;f--;)l[u._props[f]]=h;return u}function gc(t,r,e,i){var n,a,s=r.ease||i||"power1.inOut";if(Z(r))a=e[t]||(e[t]=[]),r.forEach(function(t,e){return a.push({t:e/(r.length-1)*100,v:t,e:s})});else for(n in r)a=e[n]||(e[n]=[]),"ease"===n||a.push({t:parseFloat(t),v:r[n],e:s})}var Nt,Gt,Wt=function _addPropTween(t,e,i,n,a,o,u,h,l,f){s(n)&&(n=n(a||0,t,o));var d,c=t[e],p="get"!==i?i:s(c)?l?t[e.indexOf("set")||!s(t["get"+e.substr(3)])?e:"get"+e.substr(3)](l):t[e]():c,_=s(c)?l?re:te:Zt;if(r(n)&&(~n.indexOf("random(")&&(n=ob(n)),"="===n.charAt(1)&&(!(d=ka(p,n)+(Ya(p)||0))&&0!==d||(n=d))),!f||p!==n||Gt)return isNaN(p*n)||""===n?(c||e in t||Q(e,n),function _addComplexStringPropTween(t,e,r,i,n,a,s){var o,u,h,l,f,d,c,p,_=new _e(this._pt,t,e,0,1,ue,null,n),m=0,g=0;for(_.b=r,_.e=i,r+="",(c=~(i+="").indexOf("random("))&&(i=ob(i)),a&&(a(p=[r,i],t,e),r=p[0],i=p[1]),u=r.match(it)||[];o=it.exec(i);)l=o[0],f=i.substring(m,o.index),h?h=(h+1)%5:"rgba("===f.substr(-5)&&(h=1),l!==u[g++]&&(d=parseFloat(u[g-1])||0,_._pt={_next:_._pt,p:f||1===g?f:",",s:d,c:"="===l.charAt(1)?ka(d,l)-d:parseFloat(l)-d,m:h&&h<4?Math.round:0},m=it.lastIndex);return _.c=m")}),s.duration();else{for(l in u={},x)"ease"===l||"easeEach"===l||gc(l,x[l],u,x.easeEach);for(l in u)for(A=u[l].sort(function(t,e){return t.t-e.t}),o=E=0;o=t._tDur||e<0)&&t.ratio===u&&(u&&za(t,1),r||L||(Ct(t,u?"onComplete":"onReverseComplete",!0),t._prom&&t._prom()))}else t._zTime||(t._zTime=e)}(this,t,e,r);return this},e.targets=function targets(){return this._targets},e.invalidate=function invalidate(t){return t&&this.vars.runBackwards||(this._startAt=0),this._pt=this._op=this._onUpdate=this._lazy=this.ratio=0,this._ptLookup=[],this.timeline&&this.timeline.invalidate(t),D.prototype.invalidate.call(this,t)},e.resetTo=function resetTo(t,e,r,i,n){c||Rt.wake(),this._ts||this.play();var a,s=Math.min(this._dur,(this._dp._time-this._start)*this._ts);return this._initted||Qt(this,s),a=this._ease(s/this._dur),function _updatePropTweens(t,e,r,i,n,a,s,o){var u,h,l,f,d=(t._pt&&t._ptCache||(t._ptCache={}))[e];if(!d)for(d=t._ptCache[e]=[],l=t._ptLookup,f=t._targets.length;f--;){if((u=l[f][e])&&u.d&&u.d._pt)for(u=u.d._pt;u&&u.p!==e&&u.fp!==e;)u=u._next;if(!u)return Gt=1,t.vars[e]="+=0",Qt(t,s),Gt=0,o?R(e+" not eligible for reset"):1;d.push(u)}for(f=d.length;f--;)(u=(h=d[f])._pt||h).s=!i&&0!==i||n?u.s+(i||0)+a*u.c:i,u.c=r-u.s,h.e&&(h.e=ia(r)+Ya(h.e)),h.b&&(h.b=u.s+Ya(h.b))}(this,t,e,r,i,a,s,n)?this.resetTo(t,e,r,i,1):(Ia(this,0),this.parent||xa(this._dp,this,"_first","_last",this._dp._sort?"_start":0),this.render(0))},e.kill=function kill(t,e){if(void 0===e&&(e="all"),!(t||e&&"all"!==e))return this._lazy=this._pt=0,this.parent?tb(this):this;if(this.timeline){var i=this.timeline.totalDuration();return this.timeline.killTweensOf(t,e,Nt&&!0!==Nt.vars.overwrite)._first||tb(this),this.parent&&i!==this.timeline.totalDuration()&&Ra(this,this._dur*this.timeline._tDur/i,0,1),this}var n,a,s,o,u,h,l,f=this._targets,d=t?Mt(t):f,c=this._ptLookup,p=this._pt;if((!e||"all"===e)&&function _arraysMatch(t,e){for(var r=t.length,i=r===e.length;i&&r--&&t[r]===e[r];);return r<0}(f,d))return"all"===e&&(this._pt=0),tb(this);for(n=this._op=this._op||[],"all"!==e&&(r(e)&&(u={},ha(e,function(t){return u[t]=1}),e=u),e=function _addAliasesToVars(t,e){var r,i,n,a,s=t[0]?fa(t[0]).harness:0,o=s&&s.aliases;if(!o)return e;for(i in r=yt({},e),o)if(i in r)for(n=(a=o[i].split(",")).length;n--;)r[a[n]]=r[i];return r}(f,e)),l=f.length;l--;)if(~d.indexOf(f[l]))for(u in a=c[l],"all"===e?(n[l]=e,o=a,s={}):(s=n[l]=n[l]||{},o=e),o)(h=a&&a[u])&&("kill"in h.d&&!0!==h.d.kill(u)||ya(this,h,"_pt"),delete a[u]),"all"!==s&&(s[u]=1);return this._initted&&!this._pt&&p&&tb(this),this},Tween.to=function to(t,e,r){return new Tween(t,e,r)},Tween.from=function from(t,e){return Va(1,arguments)},Tween.delayedCall=function delayedCall(t,e,r,i){return new Tween(e,0,{immediateRender:!1,lazy:!1,overwrite:!1,delay:t,onComplete:e,onReverseComplete:e,onCompleteParams:r,onReverseCompleteParams:r,callbackScope:i})},Tween.fromTo=function fromTo(t,e,r){return Va(2,arguments)},Tween.set=function set(t,e){return e.duration=0,e.repeatDelay||(e.repeat=0),new Tween(t,e)},Tween.killTweensOf=function killTweensOf(t,e,r){return I.killTweensOf(t,e,r)},Tween}(Ut);qa($t.prototype,{_targets:[],_lazy:0,_startAt:0,_op:0,_onInit:0}),ha("staggerTo,staggerFrom,staggerFromTo",function(r){$t[r]=function(){var t=new Xt,e=kt.call(arguments,0);return e.splice("staggerFromTo"===r?5:4,0,0),t[r].apply(t,e)}});function oc(t,e,r){return t.setAttribute(e,r)}function wc(t,e,r,i){i.mSet(t,e,i.m.call(i.tween,r,i.mt),i)}var Zt=function _setterPlain(t,e,r){return t[e]=r},te=function _setterFunc(t,e,r){return t[e](r)},re=function _setterFuncWithParam(t,e,r,i){return t[e](i.fp,r)},ne=function _getSetter(t,e){return s(t[e])?te:u(t[e])&&t.setAttribute?oc:Zt},ae=function _renderPlain(t,e){return e.set(e.t,e.p,Math.round(1e6*(e.s+e.c*t))/1e6,e)},se=function _renderBoolean(t,e){return e.set(e.t,e.p,!!(e.s+e.c*t),e)},ue=function _renderComplexString(t,e){var r=e._pt,i="";if(!t&&e.b)i=e.b;else if(1===t&&e.e)i=e.e;else{for(;r;)i=r.p+(r.m?r.m(r.s+r.c*t):Math.round(1e4*(r.s+r.c*t))/1e4)+i,r=r._next;i+=e.c}e.set(e.t,e.p,i,e)},he=function _renderPropTweens(t,e){for(var r=e._pt;r;)r.r(t,r.d),r=r._next},fe=function _addPluginModifier(t,e,r,i){for(var n,a=this._pt;a;)n=a._next,a.p===i&&a.modifier(t,e,r),a=n},ce=function _killPropTweensOf(t){for(var e,r,i=this._pt;i;)r=i._next,i.p===t&&!i.op||i.op===t?ya(this,i,"_pt"):i.dep||(e=1),i=r;return!e},pe=function _sortPropTweensByPriority(t){for(var e,r,i,n,a=t._pt;a;){for(e=a._next,r=i;r&&r.pr>a.pr;)r=r._next;(a._prev=r?r._prev:n)?a._prev._next=a:i=a,(a._next=r)?r._prev=a:n=a,a=e}t._pt=i},_e=(PropTween.prototype.modifier=function modifier(t,e,r){this.mSet=this.mSet||this.set,this.set=wc,this.m=t,this.mt=r,this.tween=e},PropTween);function PropTween(t,e,r,i,n,a,s,o,u){this.t=e,this.s=i,this.c=n,this.p=r,this.r=a||ae,this.d=s||this,this.set=o||Zt,this.pr=u||0,(this._next=t)&&(t._prev=this)}ha(vt+"parent,duration,ease,delay,overwrite,runBackwards,startAt,yoyo,immediateRender,repeat,repeatDelay,data,paused,reversed,lazy,callbackScope,stringFilter,id,yoyoEase,stagger,inherit,repeatRefresh,keyframes,autoRevert,scrollTrigger",function(t){return ft[t]=1}),ot.TweenMax=ot.TweenLite=$t,ot.TimelineLite=ot.TimelineMax=Xt,I=new Xt({sortChildren:!1,defaults:V,autoRemoveChildren:!0,id:"root",smoothChildTiming:!0}),q.stringFilter=Fb;function Ec(t){return(ye[t]||Te).map(function(t){return t()})}function Fc(){var t=Date.now(),o=[];2{setTimeout((()=>{this.progress(t,e,i)}))};this.images.forEach((function(e){e.once("progress",t),e.check()}))},n.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent("progress",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount===this.images.length&&this.complete(),this.options.debug&&s&&s.log(`progress: ${i}`,t,e)},n.prototype.complete=function(){let t=this.hasAnyBroken?"fail":"done";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent("always",[this]),this.jqDeferred){let t=this.hasAnyBroken?"reject":"resolve";this.jqDeferred[t](this)}},h.prototype=Object.create(e.prototype),h.prototype.check=function(){this.getIsImageComplete()?this.confirm(0!==this.img.naturalWidth,"naturalWidth"):(this.proxyImage=new Image,this.img.crossOrigin&&(this.proxyImage.crossOrigin=this.img.crossOrigin),this.proxyImage.addEventListener("load",this),this.proxyImage.addEventListener("error",this),this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.proxyImage.src=this.img.currentSrc||this.img.src)},h.prototype.getIsImageComplete=function(){return this.img.complete&&this.img.naturalWidth},h.prototype.confirm=function(t,e){this.isLoaded=t;let{parentNode:i}=this.img,s="PICTURE"===i.nodeName?i:this.img;this.emitEvent("progress",[this,s,e])},h.prototype.handleEvent=function(t){let e="on"+t.type;this[e]&&this[e](t)},h.prototype.onload=function(){this.confirm(!0,"onload"),this.unbindEvents()},h.prototype.onerror=function(){this.confirm(!1,"onerror"),this.unbindEvents()},h.prototype.unbindEvents=function(){this.proxyImage.removeEventListener("load",this),this.proxyImage.removeEventListener("error",this),this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},d.prototype=Object.create(h.prototype),d.prototype.check=function(){this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.img.src=this.url,this.getIsImageComplete()&&(this.confirm(0!==this.img.naturalWidth,"naturalWidth"),this.unbindEvents())},d.prototype.unbindEvents=function(){this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},d.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent("progress",[this,this.element,e])},n.makeJQueryPlugin=function(e){(e=e||t.jQuery)&&(i=e,i.fn.imagesLoaded=function(t,e){return new n(this,t,e).jqDeferred.promise(i(this))})},n.makeJQueryPlugin(),n})); -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | // Importing utility function for preloading images 2 | import { preloadImages } from './utils.js'; 3 | // Importing StackMotionEffect classes from different effect files with renamed imports to avoid name conflicts 4 | import { StackMotionEffect as StackMotionEffect1 } from './effect-1/stackMotionEffect.js'; 5 | import { StackMotionEffect as StackMotionEffect2 } from './effect-2/stackMotionEffect.js'; 6 | import { StackMotionEffect as StackMotionEffect3 } from './effect-3/stackMotionEffect.js'; 7 | 8 | // Registers ScrollTrigger plugin with GSAP for scroll-based animations. 9 | gsap.registerPlugin(ScrollTrigger); 10 | 11 | // Initialize function to set up motion effects and animations 12 | const init = () => { 13 | // Apply the first stack motion effect to all elements with a specific data attribute 14 | document.querySelectorAll('[data-stack-1]').forEach((stackEl) => { 15 | new StackMotionEffect1(stackEl); 16 | }); 17 | // Apply the second stack motion effect to all elements with a different specific data attribute 18 | document.querySelectorAll('[data-stack-2]').forEach((stackEl) => { 19 | new StackMotionEffect2(stackEl); 20 | }); 21 | // Apply the third stack motion effect to all elements with yet another specific data attribute 22 | document.querySelectorAll('[data-stack-3]').forEach((stackEl) => { 23 | new StackMotionEffect3(stackEl); 24 | }); 25 | 26 | // Select all grid intro card elements and apply animations on scroll 27 | const introCards = document.querySelectorAll('.intro .card'); 28 | introCards.forEach(introCard => { 29 | gsap.to(introCard, { 30 | ease: 'power1.in', 31 | startAt: { 32 | transformOrigin: '100% 50%', 33 | filter: 'brightness(70%)' 34 | }, 35 | rotationX: () => -60, 36 | yPercent: () => gsap.utils.random(-100,0), 37 | z: () => gsap.utils.random(-100,0), 38 | filter: 'brightness(0%)', 39 | scrollTrigger: { 40 | trigger: introCard, 41 | start: 'clamp(top bottom)', 42 | end: 'clamp(bottom top)', 43 | scrub: true, 44 | } 45 | }); 46 | }); 47 | }; 48 | 49 | // Preloading images and initializing setup when complete 50 | preloadImages('.grid__img').then(() => { 51 | document.body.classList.remove('loading'); 52 | init(); 53 | }); 54 | -------------------------------------------------------------------------------- /js/lenis.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t||self).Lenis=e()}(this,function(){function t(t,e){for(var i=0;i1,hasPointer:!!window.navigator.msPointerEnabled,hasKeyDown:"onkeydown"in document,isFirefox:navigator.userAgent.indexOf("Firefox")>-1}),i(this,l)[l]=Object.assign({mouseMultiplier:1,touchMultiplier:2,firefoxMultiplier:15,keyStep:120,preventTouch:!1,unpreventTouchClass:"vs-touchmove-allowed",useKeyboard:!0,useTouch:!0},t),i(this,a)[a]=new n,i(this,c)[c]={y:0,x:0,deltaX:0,deltaY:0},i(this,u)[u]={x:null,y:null},i(this,d)[d]=null,void 0!==i(this,l)[l].passive&&(this.listenerOptions={passive:i(this,l)[l].passive})}var e=t.prototype;return e._notify=function(t){var e=i(this,c)[c];e.x+=e.deltaX,e.y+=e.deltaY,i(this,a)[a].emit(s,{x:e.x,y:e.y,deltaX:e.deltaX,deltaY:e.deltaY,originalEvent:t})},e._bind=function(){r.hasWheelEvent&&i(this,h)[h].addEventListener("wheel",this._onWheel,this.listenerOptions),r.hasMouseWheelEvent&&i(this,h)[h].addEventListener("mousewheel",this._onMouseWheel,this.listenerOptions),r.hasTouch&&i(this,l)[l].useTouch&&(i(this,h)[h].addEventListener("touchstart",this._onTouchStart,this.listenerOptions),i(this,h)[h].addEventListener("touchmove",this._onTouchMove,this.listenerOptions)),r.hasPointer&&r.hasTouchWin&&(i(this,d)[d]=document.body.style.msTouchAction,document.body.style.msTouchAction="none",i(this,h)[h].addEventListener("MSPointerDown",this._onTouchStart,!0),i(this,h)[h].addEventListener("MSPointerMove",this._onTouchMove,!0)),r.hasKeyDown&&i(this,l)[l].useKeyboard&&document.addEventListener("keydown",this._onKeyDown)},e._unbind=function(){r.hasWheelEvent&&i(this,h)[h].removeEventListener("wheel",this._onWheel),r.hasMouseWheelEvent&&i(this,h)[h].removeEventListener("mousewheel",this._onMouseWheel),r.hasTouch&&(i(this,h)[h].removeEventListener("touchstart",this._onTouchStart),i(this,h)[h].removeEventListener("touchmove",this._onTouchMove)),r.hasPointer&&r.hasTouchWin&&(document.body.style.msTouchAction=i(this,d)[d],i(this,h)[h].removeEventListener("MSPointerDown",this._onTouchStart,!0),i(this,h)[h].removeEventListener("MSPointerMove",this._onTouchMove,!0)),r.hasKeyDown&&i(this,l)[l].useKeyboard&&document.removeEventListener("keydown",this._onKeyDown)},e.on=function(t,e){i(this,a)[a].on(s,t,e);var o=i(this,a)[a].e;o&&o[s]&&1===o[s].length&&this._bind()},e.off=function(t,e){i(this,a)[a].off(s,t,e);var o=i(this,a)[a].e;(!o[s]||o[s].length<=0)&&this._unbind()},e.destroy=function(){i(this,a)[a].off(),this._unbind()},t}()}()}(e),e.exports}();function l(t,e){var i=t%e;return(e>0&&i<0||e<0&&i>0)&&(i+=e),i}var h=["duration","easing"],a=/*#__PURE__*/function(){function t(){}var o=t.prototype;return o.to=function(t,e){var o=this,n=void 0===e?{}:e,r=n.duration,s=void 0===r?1:r,l=n.easing,a=void 0===l?function(t){return t}:l,c=function(t,e){if(null==t)return{};var i,o,n={},r=Object.keys(t);for(o=0;o=0||(n[i]=t[i]);return n}(n,h);this.target=t,this.fromKeys=i({},c),this.toKeys=i({},c),this.keys=Object.keys(i({},c)),this.keys.forEach(function(e){o.fromKeys[e]=t[e]}),this.duration=s,this.easing=a,this.currentTime=0,this.isRunning=!0},o.stop=function(){this.isRunning=!1},o.raf=function(t){var e=this;if(this.isRunning){this.currentTime=Math.min(this.currentTime+t,this.duration);var i=this.progress>=1?1:this.easing(this.progress);this.keys.forEach(function(t){var o=e.fromKeys[t];e.target[t]=o+(e.toKeys[t]-o)*i}),1===i&&this.stop()}},e(t,[{key:"progress",get:function(){return this.currentTime/this.duration}}]),t}();/*#__PURE__*/ 2 | return function(t){var i,n;function r(e){var i,o,n,r,l=void 0===e?{}:e,h=l.duration,c=void 0===h?1.2:h,u=l.easing,d=void 0===u?function(t){return Math.min(1,1.001-Math.pow(2,-10*t))}:u,p=l.smooth,f=void 0===p||p,v=l.mouseMultiplier,w=void 0===v?1:v,y=l.smoothTouch,m=void 0!==y&&y,g=l.touchMultiplier,b=void 0===g?2:g,T=l.direction,M=void 0===T?"vertical":T,S=l.gestureDirection,_=void 0===S?"vertical":S,O=l.infinite,E=void 0!==O&&O,W=l.wrapper,x=void 0===W?window:W,D=l.content,N=void 0===D?document.body:D;(r=t.call(this)||this).onWindowResize=function(){r.wrapperWidth=window.innerWidth,r.wrapperHeight=window.innerHeight},r.onWrapperResize=function(t){var e=t[0];if(e){var i=e.contentRect;r.wrapperWidth=i.width,r.wrapperHeight=i.height}},r.onContentResize=function(t){var e=t[0];if(e){var i=e.contentRect;r.contentWidth=i.width,r.contentHeight=i.height}},r.onVirtualScroll=function(t){var e=t.deltaY,i=t.deltaX,o=t.originalEvent;if(!("vertical"===r.gestureDirection&&0===e||"horizontal"===r.gestureDirection&&0===i)){var n=!!o.composedPath().find(function(t){return t.hasAttribute&&t.hasAttribute("data-lenis-prevent")});o.ctrlKey||n||(r.smooth=o.changedTouches?r.smoothTouch:r.options.smooth,r.stopped?o.preventDefault():r.smooth&&4!==o.buttons&&(r.smooth&&o.preventDefault(),r.targetScroll-="both"===r.gestureDirection?i+e:"horizontal"===r.gestureDirection?i:e,r.scrollTo(r.targetScroll)))}},r.onScroll=function(t){r.isScrolling&&r.smooth||(r.targetScroll=r.scroll=r.lastScroll=r.wrapperNode[r.scrollProperty],r.notify())},window.lenisVersion="0.2.28",r.options={duration:c,easing:d,smooth:f,mouseMultiplier:w,smoothTouch:m,touchMultiplier:b,direction:M,gestureDirection:_,infinite:E,wrapper:x,content:N},r.duration=c,r.easing=d,r.smooth=f,r.mouseMultiplier=w,r.smoothTouch=m,r.touchMultiplier=b,r.direction=M,r.gestureDirection=_,r.infinite=E,r.wrapperNode=x,r.contentNode=N,r.wrapperNode.addEventListener("scroll",r.onScroll),r.wrapperNode===window?(r.wrapperNode.addEventListener("resize",r.onWindowResize),r.onWindowResize()):(r.wrapperHeight=r.wrapperNode.offsetHeight,r.wrapperWidth=r.wrapperNode.offsetWidth,r.wrapperObserver=new ResizeObserver(r.onWrapperResize),r.wrapperObserver.observe(r.wrapperNode)),r.contentHeight=r.contentNode.offsetHeight,r.contentWidth=r.contentNode.offsetWidth,r.contentObserver=new ResizeObserver(r.onContentResize),r.contentObserver.observe(r.contentNode),r.targetScroll=r.scroll=r.lastScroll=r.wrapperNode[r.scrollProperty],r.animate=new a;var P=(null==(i=navigator)||null==(o=i.userAgentData)?void 0:o.platform)||(null==(n=navigator)?void 0:n.platform)||"unknown";return r.virtualScroll=new s({el:r.wrapperNode,firefoxMultiplier:50,mouseMultiplier:r.mouseMultiplier*(P.includes("Win")||P.includes("Linux")?.84:.4),touchMultiplier:r.touchMultiplier,passive:!1,useKeyboard:!1,useTouch:!0}),r.virtualScroll.on(r.onVirtualScroll),r}n=t,(i=r).prototype=Object.create(n.prototype),i.prototype.constructor=i,o(i,n);var h=r.prototype;return h.start=function(){var t=this.wrapperNode;this.wrapperNode===window&&(t=document.documentElement),t.classList.remove("lenis-stopped"),this.stopped=!1},h.stop=function(){var t=this.wrapperNode;this.wrapperNode===window&&(t=document.documentElement),t.classList.add("lenis-stopped"),this.stopped=!0,this.animate.stop()},h.destroy=function(){var t;this.wrapperNode===window&&this.wrapperNode.removeEventListener("resize",this.onWindowResize),this.wrapperNode.removeEventListener("scroll",this.onScroll),this.virtualScroll.destroy(),null==(t=this.wrapperObserver)||t.disconnect(),this.contentObserver.disconnect()},h.raf=function(t){var e=t-(this.now||0);this.now=t,!this.stopped&&this.smooth&&(this.lastScroll=this.scroll,this.animate.raf(.001*e),this.scroll===this.targetScroll&&(this.lastScroll=this.scroll),this.isScrolling&&(this.setScroll(this.scroll),this.notify()),this.isScrolling=this.scroll!==this.targetScroll)},h.setScroll=function(t){var e=this.infinite?l(t,this.limit):t;"horizontal"===this.direction?this.wrapperNode.scrollTo(e,0):this.wrapperNode.scrollTo(0,e)},h.notify=function(){var t=this.infinite?l(this.scroll,this.limit):this.scroll;this.emit("scroll",{scroll:t,limit:this.limit,velocity:this.velocity,direction:0===this.velocity?0:this.velocity>0?1:-1,progress:t/this.limit})},h.scrollTo=function(t,e){var i=void 0===e?{}:e,o=i.offset,n=void 0===o?0:o,r=i.immediate,s=void 0!==r&&r,l=i.duration,h=void 0===l?this.duration:l,a=i.easing,c=void 0===a?this.easing:a;if(null!=t&&!this.stopped){var u;if("number"==typeof t)u=t;else if("top"===t||"#top"===t)u=0;else if("bottom"===t)u=this.limit;else{var d;if("string"==typeof t)d=document.querySelector(t);else{if(null==t||!t.nodeType)return;d=t}if(!d)return;var p=0;if(this.wrapperNode!==window){var f=this.wrapperNode.getBoundingClientRect();p="horizontal"===this.direction?f.left:f.top}var v=d.getBoundingClientRect();u=("horizontal"===this.direction?v.left:v.top)+this.scroll-p}u+=n,this.targetScroll=this.infinite?u:Math.max(0,Math.min(u,this.limit)),!this.smooth||s?(this.animate.stop(),this.scroll=this.lastScroll=this.targetScroll,this.setScroll(this.targetScroll)):this.animate.to(this,{duration:h,easing:c,scroll:this.targetScroll})}},e(r,[{key:"scrollProperty",get:function(){return this.wrapperNode===window?"horizontal"===this.direction?"scrollX":"scrollY":"horizontal"===this.direction?"scrollLeft":"scrollTop"}},{key:"limit",get:function(){return"horizontal"===this.direction?this.contentWidth-this.wrapperWidth:this.contentHeight-this.wrapperHeight}},{key:"velocity",get:function(){return this.scroll-this.lastScroll}}]),r}(r)}); -------------------------------------------------------------------------------- /js/smoothscroll.js: -------------------------------------------------------------------------------- 1 | // Initializes smooth scrolling with Lenis and integrates it with GSAP's ScrollTrigger. 2 | // Function to set up smooth scrolling. 3 | const initSmoothScrolling = () => { 4 | // Initialize Lenis for smooth scroll effects. Lerp value controls the smoothness. 5 | const lenis = new Lenis({ lerp: 0.2 }); 6 | 7 | // Sync ScrollTrigger with Lenis' scroll updates. 8 | lenis.on('scroll', ScrollTrigger.update); 9 | 10 | // Ensure GSAP animations are in sync with Lenis' scroll frame updates. 11 | gsap.ticker.add((time) => { 12 | lenis.raf(time * 1000); // Convert GSAP's time to milliseconds for Lenis. 13 | }); 14 | 15 | // Turn off GSAP's default lag smoothing to avoid conflicts with Lenis. 16 | gsap.ticker.lagSmoothing(0); 17 | }; 18 | 19 | // Activate the smooth scrolling feature. 20 | initSmoothScrolling(); 21 | -------------------------------------------------------------------------------- /js/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Preloads images specified by the CSS selector. 3 | * @function 4 | * @param {string} [selector='img'] - CSS selector for target images. 5 | * @returns {Promise} - Resolves when all specified images are loaded. 6 | */ 7 | export const preloadImages = (selector = 'img') => { 8 | return new Promise((resolve) => { 9 | // The imagesLoaded library is used to ensure all images (including backgrounds) are fully loaded. 10 | imagesLoaded(document.querySelectorAll(selector), {background: true}, resolve); 11 | }); 12 | }; 13 | 14 | /** 15 | * Throttles a function call, allowing it to be executed only once every specified time period. 16 | * This is useful for controlling the rate at which a function is executed, preventing it from being called too frequently. 17 | * @function 18 | * @param {Function} func - The function to be throttled. 19 | * @param {number} limit - The time, in milliseconds, to wait before allowing the function to be called again. 20 | * @returns {Function} - A throttled version of the passed function, which when invoked, will only execute 21 | * at most once in every `limit` milliseconds, and ignores subsequent calls within the same period. 22 | */ 23 | export const throttle = (func, limit) => { 24 | let inThrottle; 25 | return function() { 26 | const args = arguments; 27 | const context = this; 28 | if (!inThrottle) { 29 | func.apply(context, args); 30 | inThrottle = true; 31 | setTimeout(() => inThrottle = false, limit); 32 | } 33 | }; 34 | }; --------------------------------------------------------------------------------