├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── css └── base.css ├── favicon.ico ├── img ├── 1.jpg ├── 10.jpg ├── 11.jpg ├── 12.jpg ├── 13.jpg ├── 14.jpg ├── 15.jpg ├── 16.jpg ├── 17.jpg ├── 18.jpg ├── 19.jpg ├── 2.jpg ├── 20.jpg ├── 21.jpg ├── 22.jpg ├── 23.jpg ├── 24.jpg ├── 25.jpg ├── 26.jpg ├── 27.jpg ├── 28.jpg ├── 29.jpg ├── 3.jpg ├── 30.jpg ├── 31.jpg ├── 32.jpg ├── 33.jpg ├── 34.jpg ├── 35.jpg ├── 36.jpg ├── 37.jpg ├── 38.jpg ├── 39.jpg ├── 4.jpg ├── 40.jpg ├── 41.jpg ├── 42.jpg ├── 43.jpg ├── 44.jpg ├── 45.jpg ├── 46.jpg ├── 47.jpg ├── 48.jpg ├── 49.jpg ├── 5.jpg ├── 50.jpg ├── 51.jpg ├── 52.jpg ├── 53.jpg ├── 54.jpg ├── 55.jpg ├── 6.jpg ├── 7.jpg ├── 8.jpg └── 9.jpg ├── index.html ├── index10.html ├── index11.html ├── index12.html ├── index13.html ├── index14.html ├── index15.html ├── index16.html ├── index2.html ├── index3.html ├── index4.html ├── index5.html ├── index6.html ├── index7.html ├── index8.html ├── index9.html └── js ├── Observer.min.js ├── demo1 ├── index.js └── slideshow.js ├── demo10 ├── index.js └── slideshow.js ├── demo11 ├── index.js └── slideshow.js ├── demo12 ├── index.js └── slideshow.js ├── demo13 ├── index.js └── slideshow.js ├── demo14 ├── index.js └── slideshow.js ├── demo15 ├── index.js └── slideshow.js ├── demo16 ├── index.js └── slideshow.js ├── demo2 ├── index.js └── slideshow.js ├── demo3 ├── index.js └── slideshow.js ├── demo4 ├── index.js └── slideshow.js ├── demo5 ├── index.js └── slideshow.js ├── demo6 ├── index.js └── slideshow.js ├── demo7 ├── index.js └── slideshow.js ├── demo8 ├── index.js └── slideshow.js ├── demo9 ├── index.js └── slideshow.js ├── gsap.min.js ├── imagesloaded.pkgd.min.js └── utils.js /.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 - 2022 [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 | # Slideshow Animations 2 | 3 | A collection of ideas for slideshow animations. 4 | 5 | ![Slideshow Animations](https://tympanus.net/codrops/wp-content/uploads/2023/09/slideshowanimations-1.jpg) 6 | 7 | [Article on Codrops](https://tympanus.net/codrops/?p=73708) 8 | 9 | [Demo](http://tympanus.net/Development/SlideshowAnimations/) 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: [Twitter](http://www.twitter.com/codrops), [Facebook](http://www.facebook.com/codrops), [GitHub](https://github.com/codrops), [Instagram](https://www.instagram.com/codropsss/) 22 | 23 | ## License 24 | [MIT](LICENSE) 25 | 26 | Made with :blue_heart: by [Codrops](http://www.codrops.com) 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 16px; 9 | --color-text: #fff; 10 | --color-bg: #000; 11 | --color-link: #fff; 12 | --color-link-hover: #fff; 13 | } 14 | 15 | body { 16 | margin: 0; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: 'area-normal', -apple-system, BlinkMacSystemFont, Segoe UI, 20 | Helvetica, Arial, sans-serif; 21 | font-family: 'anonymous-pro', monospace; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | height: 100%; 25 | overflow: hidden; 26 | } 27 | 28 | /* Page Loader */ 29 | .js .loading::before, 30 | .js .loading::after { 31 | content: ''; 32 | position: fixed; 33 | z-index: 1000; 34 | } 35 | 36 | .js .loading::before { 37 | top: 0; 38 | left: 0; 39 | width: 100%; 40 | height: 100%; 41 | background: var(--color-bg); 42 | } 43 | 44 | .js .loading::after { 45 | top: 50%; 46 | left: 50%; 47 | width: 60px; 48 | height: 60px; 49 | margin: -30px 0 0 -30px; 50 | border-radius: 50%; 51 | opacity: 0.4; 52 | background: var(--color-link); 53 | animation: loaderAnim 0.7s linear infinite alternate forwards; 54 | } 55 | 56 | @keyframes loaderAnim { 57 | to { 58 | opacity: 1; 59 | transform: scale3d(0.5, 0.5, 1); 60 | } 61 | } 62 | 63 | a { 64 | text-decoration: none; 65 | color: var(--color-link); 66 | outline: none; 67 | cursor: pointer; 68 | } 69 | 70 | a:hover { 71 | color: var(--color-link-hover); 72 | outline: none; 73 | } 74 | 75 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 76 | a:focus { 77 | /* Provide a fallback style for browsers 78 | that don't support :focus-visible */ 79 | outline: none; 80 | background: lightgrey; 81 | } 82 | 83 | a:focus:not(:focus-visible) { 84 | /* Remove the focus indicator on mouse-focus for browsers 85 | that do support :focus-visible */ 86 | background: transparent; 87 | } 88 | 89 | a:focus-visible { 90 | /* Draw a very noticeable focus style for 91 | keyboard-focus on browsers that do support 92 | :focus-visible */ 93 | outline: 2px solid red; 94 | background: transparent; 95 | } 96 | 97 | .unbutton { 98 | background: none; 99 | border: 0; 100 | padding: 0; 101 | margin: 0; 102 | font: inherit; 103 | cursor: pointer; 104 | } 105 | 106 | .unbutton:focus { 107 | outline: none; 108 | } 109 | 110 | .frame { 111 | position: fixed; 112 | top: 0; 113 | left: 0; 114 | width: 100%; 115 | height: 100vh; 116 | color: var(--color-title); 117 | padding: 2rem; 118 | display: grid; 119 | grid-template-columns: auto 1fr; 120 | grid-template-rows: auto auto auto auto 1fr; 121 | grid-template-areas: 'title title' 'prev back' 'demos demos' 'sponsor sponsor' 'nav nav'; 122 | justify-content: start; 123 | align-content: start; 124 | align-items: start; 125 | z-index: 100; 126 | pointer-events: none; 127 | grid-gap: 1rem; 128 | } 129 | 130 | body #cdawrap { 131 | align-self: start; 132 | justify-self: start; 133 | } 134 | 135 | .frame a, 136 | .frame button { 137 | pointer-events: auto; 138 | } 139 | 140 | .frame__title { 141 | grid-area: title; 142 | display: flex; 143 | align-items: flex-end; 144 | font-weight: 400; 145 | } 146 | 147 | .frame strong { 148 | font-weight: 700; 149 | } 150 | 151 | .frame__title-main { 152 | font-size: inherit; 153 | margin: 0; 154 | font-weight: inherit; 155 | } 156 | 157 | .frame__back { 158 | grid-area: back; 159 | } 160 | 161 | .frame__prev { 162 | grid-area: prev; 163 | } 164 | 165 | .frame__demos { 166 | grid-area: demos; 167 | display: grid; 168 | grid-template-columns: repeat(8, auto); 169 | column-gap: 1rem; 170 | row-gap: 0.5rem; 171 | } 172 | 173 | .frame__demos span { 174 | grid-column: 1 / span 8; 175 | } 176 | 177 | a.frame__demo { 178 | font-weight: 400; 179 | font-size: 1rem; 180 | text-decoration: none; 181 | opacity: 0.5; 182 | font-family: 'anonymous-pro', monospace; 183 | } 184 | 185 | a.frame__demo--current { 186 | font-weight: 700; 187 | opacity: 1; 188 | color: var(--color-link-hover); 189 | } 190 | 191 | .slides { 192 | width: 100%; 193 | height: 100vh; 194 | overflow: hidden; 195 | display: grid; 196 | grid-template-rows: 100%; 197 | grid-template-columns: 100%; 198 | place-items: center; 199 | } 200 | 201 | .slide { 202 | width: 100%; 203 | height: 100%; 204 | grid-area: 1 / 1 / -1 / -1; 205 | pointer-events: none; 206 | opacity: 0; 207 | overflow: hidden; 208 | position: relative; 209 | display: grid; 210 | place-items: center; 211 | will-change: transform, opacity; 212 | } 213 | 214 | .slide--current { 215 | pointer-events: auto; 216 | opacity: 1; 217 | } 218 | 219 | .deco { 220 | width: 100%; 221 | height: 100%; 222 | grid-area: 1 / 1 / -1 / -1; 223 | pointer-events: none; 224 | position: relative; 225 | opacity: 0; 226 | background: #8c718e; 227 | will-change: transform, opacity; 228 | } 229 | 230 | .deco--1 { 231 | background: #d4503e; 232 | } 233 | 234 | .deco--2 { 235 | background: #1c1a1a; 236 | } 237 | 238 | .deco--3 { 239 | background: #4e4141; 240 | } 241 | 242 | .deco--4 { 243 | background: #000; 244 | } 245 | 246 | .deco--5 { 247 | background: #060b17; 248 | } 249 | 250 | .deco--6 { 251 | background: #34365c; 252 | } 253 | 254 | .deco--7 { 255 | background: #9f6794; 256 | } 257 | 258 | .slide__img { 259 | width: 100%; 260 | height: 100%; 261 | background-size: cover; 262 | background-position: 50% 50%; 263 | background-repeat: no-repeat; 264 | will-change: transform, opacity, filter; 265 | } 266 | 267 | .demo-2 .slide__img { 268 | width: 120%; 269 | height: 120%; 270 | } 271 | 272 | .slides-nav { 273 | grid-area: nav; 274 | display: flex; 275 | gap: 0.5rem; 276 | align-self: end; 277 | align-items: center; 278 | } 279 | 280 | .slides-nav::before { 281 | content: 'scroll / drag'; 282 | margin-right: 2rem; 283 | } 284 | 285 | .slides-nav__item { 286 | border: 0; 287 | background: #fff; 288 | color: #000; 289 | width: 60px; 290 | aspect-ratio: 1; 291 | display: grid; 292 | place-items: center; 293 | border-radius: 50%; 294 | cursor: pointer; 295 | transition: background-color 0.3s; 296 | } 297 | 298 | .slides-nav__item:hover { 299 | background-color: #ccc; 300 | } 301 | 302 | @media screen and (min-width: 53em) { 303 | .frame { 304 | height: 100vh; 305 | grid-gap: 2rem; 306 | align-content: space-between; 307 | grid-template-columns: auto auto auto 1fr; 308 | grid-template-rows: auto auto; 309 | grid-template-areas: 'title back prev demos' 'sponsor ... ... nav '; 310 | } 311 | 312 | .frame__demos { 313 | justify-self: end; 314 | justify-content: end; 315 | } 316 | 317 | .frame__demos span, 318 | a.frame__demo { 319 | text-align: right; 320 | } 321 | 322 | .slides-nav { 323 | justify-self: end; 324 | } 325 | 326 | body #cdawrap { 327 | align-self: center; 328 | justify-self: start; 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/favicon.ico -------------------------------------------------------------------------------- /img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/1.jpg -------------------------------------------------------------------------------- /img/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/10.jpg -------------------------------------------------------------------------------- /img/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/11.jpg -------------------------------------------------------------------------------- /img/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/12.jpg -------------------------------------------------------------------------------- /img/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/13.jpg -------------------------------------------------------------------------------- /img/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/14.jpg -------------------------------------------------------------------------------- /img/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/15.jpg -------------------------------------------------------------------------------- /img/16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/16.jpg -------------------------------------------------------------------------------- /img/17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/17.jpg -------------------------------------------------------------------------------- /img/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/18.jpg -------------------------------------------------------------------------------- /img/19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/19.jpg -------------------------------------------------------------------------------- /img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/2.jpg -------------------------------------------------------------------------------- /img/20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/20.jpg -------------------------------------------------------------------------------- /img/21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/21.jpg -------------------------------------------------------------------------------- /img/22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/22.jpg -------------------------------------------------------------------------------- /img/23.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/23.jpg -------------------------------------------------------------------------------- /img/24.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/24.jpg -------------------------------------------------------------------------------- /img/25.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/25.jpg -------------------------------------------------------------------------------- /img/26.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/26.jpg -------------------------------------------------------------------------------- /img/27.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/27.jpg -------------------------------------------------------------------------------- /img/28.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/28.jpg -------------------------------------------------------------------------------- /img/29.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/29.jpg -------------------------------------------------------------------------------- /img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/3.jpg -------------------------------------------------------------------------------- /img/30.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/30.jpg -------------------------------------------------------------------------------- /img/31.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/31.jpg -------------------------------------------------------------------------------- /img/32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/32.jpg -------------------------------------------------------------------------------- /img/33.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/33.jpg -------------------------------------------------------------------------------- /img/34.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/34.jpg -------------------------------------------------------------------------------- /img/35.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/35.jpg -------------------------------------------------------------------------------- /img/36.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/36.jpg -------------------------------------------------------------------------------- /img/37.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/37.jpg -------------------------------------------------------------------------------- /img/38.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/38.jpg -------------------------------------------------------------------------------- /img/39.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/39.jpg -------------------------------------------------------------------------------- /img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/4.jpg -------------------------------------------------------------------------------- /img/40.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/40.jpg -------------------------------------------------------------------------------- /img/41.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/41.jpg -------------------------------------------------------------------------------- /img/42.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/42.jpg -------------------------------------------------------------------------------- /img/43.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/43.jpg -------------------------------------------------------------------------------- /img/44.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/44.jpg -------------------------------------------------------------------------------- /img/45.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/45.jpg -------------------------------------------------------------------------------- /img/46.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/46.jpg -------------------------------------------------------------------------------- /img/47.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/47.jpg -------------------------------------------------------------------------------- /img/48.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/48.jpg -------------------------------------------------------------------------------- /img/49.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/49.jpg -------------------------------------------------------------------------------- /img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/5.jpg -------------------------------------------------------------------------------- /img/50.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/50.jpg -------------------------------------------------------------------------------- /img/51.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/51.jpg -------------------------------------------------------------------------------- /img/52.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/52.jpg -------------------------------------------------------------------------------- /img/53.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/53.jpg -------------------------------------------------------------------------------- /img/54.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/54.jpg -------------------------------------------------------------------------------- /img/55.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/55.jpg -------------------------------------------------------------------------------- /img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/6.jpg -------------------------------------------------------------------------------- /img/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/7.jpg -------------------------------------------------------------------------------- /img/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/8.jpg -------------------------------------------------------------------------------- /img/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/SlideshowAnimations/8f9ee4001e0c786ec617f7f729272c4d5a0830a2/img/9.jpg -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 1 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /index10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 10 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /index11.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 11 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
108 |
109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /index12.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 12 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /index13.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 13 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /index14.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 14 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /index15.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 15 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 |
121 |
122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /index16.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 16 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 2 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /index3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 3 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /index4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 4 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /index5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 5 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /index6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 6 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /index7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 7 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /index8.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 8 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | 78 | 86 |
87 |
88 |
89 |
93 |
94 |
95 |
99 |
100 |
101 |
105 |
106 |
107 |
111 |
112 |
113 |
117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /index9.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Slideshow Animations | Demo 9 | Codrops 7 | 11 | 15 | 16 | 17 | 18 | 19 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |

48 | Slideshow Animations 49 |

50 |
51 | Article 54 | Previous demo 59 | Article 62 | Previous demo 67 | 86 | 94 |
95 |
96 |
97 |
101 |
102 |
103 |
107 |
108 |
109 |
113 |
114 |
115 |
119 |
120 |
121 |
125 |
126 |
127 |
128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /js/Observer.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Observer 3.12.2 3 | * https://greensock.com 4 | * 5 | * @license Copyright 2023, GreenSock. All rights reserved. 6 | * Subject to the terms at https://greensock.com/standard-license or for Club GreenSock 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(a){"use strict";function _defineProperties(e,t){for(var n=0;n=Math.abs(n)?t:n}function M(){(ze=we.core.globals().ScrollTrigger)&&ze.core&&function _integrate(){var e=ze.core,n=e.bridge||{},t=e._scrollers,r=e._proxies;t.push.apply(t,a._scrollers),r.push.apply(r,a._proxies),a._scrollers=t,a._proxies=r,i=function _bridge(e,t){return n[e](t)}}()}function N(e){return(we=e||r())&&"undefined"!=typeof document&&document.body&&(Pe=window,De=(Ae=document).documentElement,Ee=Ae.body,t=[Pe,Ae,De,Ee],we.utils.clamp,ke=we.core.context||function(){},Ye="onpointerenter"in Ee?"pointer":"mouse",Oe=s.isTouch=Pe.matchMedia&&Pe.matchMedia("(hover: none), (pointer: coarse)").matches?1:"ontouchstart"in Pe||0=o,r=Math.abs(t)>=o;O&&(n||r)&&O(se,e,t,ye,xe),n&&(_&&0Math.abs(t)?"x":"y",ie=!0),"y"!==ce&&(ye[2]+=e,se._vx.update(e,!0)),"x"!==ce&&(xe[2]+=t,se._vy.update(t,!0)),r?ee=ee||requestAnimationFrame(rc):rc()}function uc(e){if(!pc(e,1)){var t=(e=K(e,s)).clientX,n=e.clientY,r=t-se.x,o=n-se.y,i=se.isDragging;se.x=t,se.y=n,(i||Math.abs(se.startX-t)>=c||Math.abs(se.startY-n)>=c)&&(h&&(ne=!0),i||(se.isDragging=!0),tc(r,o),i||g&&g(se))}}function xc(e){return e.touches&&1 slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo1/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | defaults: { 104 | duration: 1.5, 105 | ease: 'power4.inOut', 106 | }, 107 | onStart: () => { 108 | // Add class to the upcoming slide to mark it as current 109 | this.DOM.slides[this.current].classList.add('slide--current'); 110 | }, 111 | onComplete: () => { 112 | // Remove class from the previous slide to unmark it as current 113 | this.DOM.slides[previous].classList.remove('slide--current'); 114 | // Reset animation flag 115 | this.isAnimating = false; 116 | }, 117 | }) 118 | // Defining animation steps 119 | .addLabel('start', 0) 120 | .to( 121 | currentSlide, 122 | { 123 | yPercent: -direction * 100, 124 | }, 125 | 'start' 126 | ) 127 | .to( 128 | currentInner, 129 | { 130 | yPercent: direction * 30, 131 | }, 132 | 'start' 133 | ) 134 | .fromTo( 135 | upcomingSlide, 136 | { 137 | yPercent: direction * 100, 138 | }, 139 | { 140 | yPercent: 0, 141 | }, 142 | 'start' 143 | ) 144 | .fromTo( 145 | upcomingInner, 146 | { 147 | yPercent: -direction * 30, 148 | //yPercent: 0 149 | }, 150 | { 151 | yPercent: 0, 152 | }, 153 | 'start' 154 | ); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /js/demo10/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo10/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | defaults: { 104 | duration: 1, 105 | ease: 'power3.inOut', 106 | }, 107 | onStart: () => { 108 | // Add class to the upcoming slide to mark it as current 109 | this.DOM.slides[this.current].classList.add('slide--current'); 110 | gsap.set(upcomingSlide, { zIndex: 99 }); 111 | }, 112 | onComplete: () => { 113 | // Remove class from the previous slide to unmark it as current 114 | this.DOM.slides[previous].classList.remove('slide--current'); 115 | gsap.set(upcomingSlide, { zIndex: 1 }); 116 | // Reset animation flag 117 | this.isAnimating = false; 118 | }, 119 | }) 120 | // Defining animation steps 121 | .addLabel('start', 0) 122 | .to( 123 | currentSlide, 124 | { 125 | xPercent: -direction * 15, 126 | yPercent: -direction * 15, 127 | autoAlpha: 0, 128 | }, 129 | 'start' 130 | ) 131 | 132 | .fromTo( 133 | upcomingSlide, 134 | { 135 | autoAlpha: 1, 136 | xPercent: direction * 100, 137 | yPercent: direction * 100, 138 | }, 139 | { 140 | xPercent: 0, 141 | yPercent: 0, 142 | }, 143 | 'start' 144 | ); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /js/demo11/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo11/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | 20 | deco: null, // Empty deco element between the slides 21 | }; 22 | /** 23 | * Index of the current slide being displayed. 24 | * @type {number} 25 | */ 26 | current = 0; 27 | /** 28 | * Total number of slides. 29 | * @type {number} 30 | */ 31 | slidesTotal = 0; 32 | 33 | /** 34 | * Flag to indicate if an animation is running. 35 | * @type {boolean} 36 | */ 37 | isAnimating = false; 38 | 39 | /** 40 | * Slideshow constructor. 41 | * Initializes the slideshow and sets up the DOM elements. 42 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 43 | */ 44 | constructor(DOM_el) { 45 | // Initialize DOM elements 46 | this.DOM.el = DOM_el; 47 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 48 | this.DOM.slidesInner = this.DOM.slides.map((item) => 49 | item.querySelector('.slide__img') 50 | ); 51 | 52 | // Set initial slide as current 53 | this.DOM.slides[this.current].classList.add('slide--current'); 54 | 55 | // Count total slides 56 | this.slidesTotal = this.DOM.slides.length; 57 | 58 | // Deco element 59 | this.DOM.deco = this.DOM.el.querySelector('.deco'); 60 | } 61 | 62 | /** 63 | * Navigate to the next slide. 64 | * @returns {void} 65 | */ 66 | next() { 67 | this.navigate(NEXT); 68 | } 69 | 70 | /** 71 | * Navigate to the previous slide. 72 | * @returns {void} 73 | */ 74 | prev() { 75 | this.navigate(PREV); 76 | } 77 | 78 | /** 79 | * Navigate through slides. 80 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 81 | * @returns {boolean} - Return false if the animation is currently running. 82 | */ 83 | navigate(direction) { 84 | // Check if animation is already running 85 | if (this.isAnimating) return false; 86 | this.isAnimating = true; 87 | 88 | // Update the current slide index based on direction 89 | const previous = this.current; 90 | this.current = 91 | direction === 1 92 | ? this.current < this.slidesTotal - 1 93 | ? ++this.current 94 | : 0 95 | : this.current > 0 96 | ? --this.current 97 | : this.slidesTotal - 1; 98 | 99 | // Get the current and upcoming slides and their inner elements 100 | const currentSlide = this.DOM.slides[previous]; 101 | const currentInner = this.DOM.slidesInner[previous]; 102 | const upcomingSlide = this.DOM.slides[this.current]; 103 | const upcomingInner = this.DOM.slidesInner[this.current]; 104 | 105 | // Animation sequence using GSAP 106 | gsap 107 | .timeline({ 108 | defaults: { 109 | duration: 1.3, 110 | }, 111 | onStart: () => { 112 | // Add class to the upcoming slide to mark it as current 113 | //this.DOM.slides[this.current].classList.add('slide--current'); 114 | }, 115 | onComplete: () => { 116 | // Remove class from the previous slide to unmark it as current 117 | this.DOM.slides[previous].classList.remove('slide--current'); 118 | // Reset animation flag 119 | this.isAnimating = false; 120 | }, 121 | }) 122 | // Defining animation steps 123 | .addLabel('start', 0) 124 | .to( 125 | currentSlide, 126 | { 127 | duration: 0.4, 128 | ease: 'power2.in', 129 | yPercent: -direction * 100, 130 | }, 131 | 'start' 132 | ) 133 | .to( 134 | currentInner, 135 | { 136 | duration: 0.4, 137 | ease: 'power2.in', 138 | yPercent: direction * 75, 139 | rotation: -direction * 2, 140 | }, 141 | 'start' 142 | ) 143 | .fromTo( 144 | this.DOM.deco, 145 | { 146 | yPercent: direction * 100, 147 | autoAlpha: 1, 148 | }, 149 | { 150 | duration: 0.4, 151 | ease: 'power2.in', 152 | yPercent: 0, 153 | }, 154 | 'start' 155 | ) 156 | 157 | .addLabel('middle', 'start+=0.5') 158 | .to( 159 | this.DOM.deco, 160 | { 161 | ease: 'expo', 162 | yPercent: -direction * 100, 163 | }, 164 | 'middle' 165 | ) 166 | .fromTo( 167 | upcomingSlide, 168 | { 169 | autoAlpha: 1, 170 | yPercent: direction * 100, 171 | }, 172 | { 173 | ease: 'expo', 174 | yPercent: 0, 175 | }, 176 | 'middle' 177 | ) 178 | .fromTo( 179 | upcomingInner, 180 | { 181 | yPercent: -direction * 75, 182 | rotation: direction * 2, 183 | }, 184 | { 185 | ease: 'expo', 186 | yPercent: 0, 187 | rotation: 0, 188 | }, 189 | 'middle' 190 | ); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /js/demo12/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo12/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | 20 | deco: null, // Empty deco element between the slides 21 | }; 22 | /** 23 | * Index of the current slide being displayed. 24 | * @type {number} 25 | */ 26 | current = 0; 27 | /** 28 | * Total number of slides. 29 | * @type {number} 30 | */ 31 | slidesTotal = 0; 32 | 33 | /** 34 | * Flag to indicate if an animation is running. 35 | * @type {boolean} 36 | */ 37 | isAnimating = false; 38 | 39 | /** 40 | * Slideshow constructor. 41 | * Initializes the slideshow and sets up the DOM elements. 42 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 43 | */ 44 | constructor(DOM_el) { 45 | // Initialize DOM elements 46 | this.DOM.el = DOM_el; 47 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 48 | this.DOM.slidesInner = this.DOM.slides.map((item) => 49 | item.querySelector('.slide__img') 50 | ); 51 | 52 | // Set initial slide as current 53 | this.DOM.slides[this.current].classList.add('slide--current'); 54 | 55 | // Count total slides 56 | this.slidesTotal = this.DOM.slides.length; 57 | 58 | // Deco element 59 | this.DOM.deco = this.DOM.el.querySelectorAll('.deco'); 60 | } 61 | 62 | /** 63 | * Navigate to the next slide. 64 | * @returns {void} 65 | */ 66 | next() { 67 | this.navigate(NEXT); 68 | } 69 | 70 | /** 71 | * Navigate to the previous slide. 72 | * @returns {void} 73 | */ 74 | prev() { 75 | this.navigate(PREV); 76 | } 77 | 78 | /** 79 | * Navigate through slides. 80 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 81 | * @returns {boolean} - Return false if the animation is currently running. 82 | */ 83 | navigate(direction) { 84 | // Check if animation is already running 85 | if (this.isAnimating) return false; 86 | this.isAnimating = true; 87 | 88 | // Update the current slide index based on direction 89 | const previous = this.current; 90 | this.current = 91 | direction === 1 92 | ? this.current < this.slidesTotal - 1 93 | ? ++this.current 94 | : 0 95 | : this.current > 0 96 | ? --this.current 97 | : this.slidesTotal - 1; 98 | 99 | // Get the current and upcoming slides and their inner elements 100 | const currentSlide = this.DOM.slides[previous]; 101 | const currentInner = this.DOM.slidesInner[previous]; 102 | const upcomingSlide = this.DOM.slides[this.current]; 103 | const upcomingInner = this.DOM.slidesInner[this.current]; 104 | 105 | // Animation sequence using GSAP 106 | this.tl = gsap 107 | .timeline({ 108 | defaults: { 109 | duration: 1.2, 110 | }, 111 | onStart: () => { 112 | // Add class to the upcoming slide to mark it as current 113 | this.DOM.slides[this.current].classList.add('slide--current'); 114 | }, 115 | onComplete: () => { 116 | // Remove class from the previous slide to unmark it as current 117 | this.DOM.slides[previous].classList.remove('slide--current'); 118 | // Reset animation flag 119 | this.isAnimating = false; 120 | }, 121 | }) 122 | // Defining animation steps 123 | .addLabel('start', 0) 124 | .to( 125 | currentSlide, 126 | { 127 | duration: 0.4, 128 | ease: 'power2.in', 129 | xPercent: -direction * 100, 130 | }, 131 | 'start' 132 | ) 133 | .to( 134 | currentInner, 135 | { 136 | duration: 0.4, 137 | ease: 'power2.in', 138 | xPercent: direction * 75, 139 | rotation: -direction * 6, 140 | }, 141 | 'start' 142 | ) 143 | .fromTo( 144 | this.DOM.deco, 145 | { 146 | xPercent: direction * 100, 147 | autoAlpha: 1, 148 | }, 149 | { 150 | duration: 0.4, 151 | ease: 'power2.in', 152 | xPercent: 0, 153 | }, 154 | 'start' 155 | ); 156 | [...this.DOM.deco].forEach((_, pos, arr) => { 157 | this.tl.to( 158 | arr[arr.length - 1 - pos], 159 | { 160 | ease: 'power4', 161 | xPercent: -direction * 100, 162 | }, 163 | `start+=${(pos + 1) * 0.2}` 164 | ); 165 | }); 166 | this.tl 167 | .addLabel('middle', '<') 168 | .fromTo( 169 | upcomingSlide, 170 | { 171 | autoAlpha: 1, 172 | xPercent: direction * 100, 173 | }, 174 | { 175 | ease: 'power4', 176 | xPercent: 0, 177 | }, 178 | 'middle' 179 | ) 180 | .fromTo( 181 | upcomingInner, 182 | { 183 | xPercent: -direction * 75, 184 | rotation: direction * 6, 185 | }, 186 | { 187 | ease: 'power4', 188 | xPercent: 0, 189 | rotation: 0, 190 | }, 191 | 'middle' 192 | ); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /js/demo13/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo13/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | gsap.set(this.DOM.el, { perspective: 1000 }); 51 | 52 | // Set initial slide as current 53 | this.DOM.slides[this.current].classList.add('slide--current'); 54 | 55 | // Count total slides 56 | this.slidesTotal = this.DOM.slides.length; 57 | } 58 | 59 | /** 60 | * Navigate to the next slide. 61 | * @returns {void} 62 | */ 63 | next() { 64 | this.navigate(NEXT); 65 | } 66 | 67 | /** 68 | * Navigate to the previous slide. 69 | * @returns {void} 70 | */ 71 | prev() { 72 | this.navigate(PREV); 73 | } 74 | 75 | /** 76 | * Navigate through slides. 77 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 78 | * @returns {boolean} - Return false if the animation is currently running. 79 | */ 80 | navigate(direction) { 81 | // Check if animation is already running 82 | if (this.isAnimating) return false; 83 | this.isAnimating = true; 84 | 85 | // Update the current slide index based on direction 86 | const previous = this.current; 87 | this.current = 88 | direction === 1 89 | ? this.current < this.slidesTotal - 1 90 | ? ++this.current 91 | : 0 92 | : this.current > 0 93 | ? --this.current 94 | : this.slidesTotal - 1; 95 | 96 | // Get the current and upcoming slides and their inner elements 97 | const currentSlide = this.DOM.slides[previous]; 98 | const currentInner = this.DOM.slidesInner[previous]; 99 | const upcomingSlide = this.DOM.slides[this.current]; 100 | const upcomingInner = this.DOM.slidesInner[this.current]; 101 | 102 | // Animation sequence using GSAP 103 | gsap 104 | .timeline({ 105 | defaults: { 106 | duration: 1.2, 107 | ease: 'power3.inOut', 108 | }, 109 | onStart: () => { 110 | // Add class to the upcoming slide to mark it as current 111 | this.DOM.slides[this.current].classList.add('slide--current'); 112 | gsap.set(upcomingSlide, { zIndex: 99 }); 113 | }, 114 | onComplete: () => { 115 | // Remove class from the previous slide to unmark it as current 116 | this.DOM.slides[previous].classList.remove('slide--current'); 117 | gsap.set(upcomingSlide, { zIndex: 1 }); 118 | // Reset animation flag 119 | this.isAnimating = false; 120 | }, 121 | }) 122 | // Defining animation steps 123 | .addLabel('start', 0) 124 | .to( 125 | currentSlide, 126 | { 127 | yPercent: -direction * 100, 128 | }, 129 | 'start' 130 | ) 131 | .fromTo( 132 | upcomingSlide, 133 | { 134 | yPercent: 0, 135 | autoAlpha: 0, 136 | rotationX: 140, 137 | scale: 0.1, 138 | z: -1000, 139 | }, 140 | { 141 | autoAlpha: 1, 142 | rotationX: 0, 143 | z: 0, 144 | scale: 1, 145 | }, 146 | 'start+=0.1' 147 | ) 148 | .fromTo( 149 | upcomingInner, 150 | { 151 | scale: 1.8, 152 | }, 153 | { 154 | scale: 1, 155 | }, 156 | 'start+=0.17' 157 | ); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /js/demo14/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo14/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | defaults: { 104 | duration: 1.2, 105 | ease: 'power4.inOut', 106 | }, 107 | onStart: () => { 108 | // Add class to the upcoming slide to mark it as current 109 | this.DOM.slides[this.current].classList.add('slide--current'); 110 | }, 111 | onComplete: () => { 112 | // Remove class from the previous slide to unmark it as current 113 | this.DOM.slides[previous].classList.remove('slide--current'); 114 | // Reset animation flag 115 | this.isAnimating = false; 116 | }, 117 | }) 118 | // Defining animation steps 119 | .addLabel('start', 0) 120 | .to( 121 | currentSlide, 122 | { 123 | startAt: { 124 | transformOrigin: direction === NEXT ? '0% 50%' : '100% 50%', 125 | }, 126 | scaleX: 0, 127 | autoAlpha: 0, 128 | }, 129 | 'start' 130 | ) 131 | .fromTo( 132 | upcomingSlide, 133 | { 134 | transformOrigin: direction === NEXT ? '100% 50%' : '0% 50%', 135 | autoAlpha: 0, 136 | scaleX: 0, 137 | }, 138 | { 139 | autoAlpha: 1, 140 | scaleX: 1, 141 | }, 142 | 'start' 143 | ); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /js/demo15/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo15/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | 20 | deco: null, // Empty deco element between the slides 21 | }; 22 | /** 23 | * Index of the current slide being displayed. 24 | * @type {number} 25 | */ 26 | current = 0; 27 | /** 28 | * Total number of slides. 29 | * @type {number} 30 | */ 31 | slidesTotal = 0; 32 | 33 | /** 34 | * Flag to indicate if an animation is running. 35 | * @type {boolean} 36 | */ 37 | isAnimating = false; 38 | 39 | /** 40 | * Slideshow constructor. 41 | * Initializes the slideshow and sets up the DOM elements. 42 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 43 | */ 44 | constructor(DOM_el) { 45 | // Initialize DOM elements 46 | this.DOM.el = DOM_el; 47 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 48 | this.DOM.slidesInner = this.DOM.slides.map((item) => 49 | item.querySelector('.slide__img') 50 | ); 51 | 52 | // Set initial slide as current 53 | this.DOM.slides[this.current].classList.add('slide--current'); 54 | 55 | // Count total slides 56 | this.slidesTotal = this.DOM.slides.length; 57 | 58 | // Deco element 59 | this.DOM.deco = this.DOM.el.querySelectorAll('.deco'); 60 | } 61 | 62 | /** 63 | * Navigate to the next slide. 64 | * @returns {void} 65 | */ 66 | next() { 67 | this.navigate(NEXT); 68 | } 69 | 70 | /** 71 | * Navigate to the previous slide. 72 | * @returns {void} 73 | */ 74 | prev() { 75 | this.navigate(PREV); 76 | } 77 | 78 | /** 79 | * Navigate through slides. 80 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 81 | * @returns {boolean} - Return false if the animation is currently running. 82 | */ 83 | navigate(direction) { 84 | // Check if animation is already running 85 | if (this.isAnimating) return false; 86 | this.isAnimating = true; 87 | 88 | // Update the current slide index based on direction 89 | const previous = this.current; 90 | this.current = 91 | direction === 1 92 | ? this.current < this.slidesTotal - 1 93 | ? ++this.current 94 | : 0 95 | : this.current > 0 96 | ? --this.current 97 | : this.slidesTotal - 1; 98 | 99 | // Get the current and upcoming slides and their inner elements 100 | const currentSlide = this.DOM.slides[previous]; 101 | const currentInner = this.DOM.slidesInner[previous]; 102 | const upcomingSlide = this.DOM.slides[this.current]; 103 | const upcomingInner = this.DOM.slidesInner[this.current]; 104 | 105 | // Animation sequence using GSAP 106 | gsap 107 | .timeline({ 108 | defaults: { 109 | duration: 0.8, 110 | ease: 'power3.inOut', 111 | }, 112 | onComplete: () => { 113 | // Reset animation flag 114 | this.isAnimating = false; 115 | }, 116 | }) 117 | // Defining animation steps 118 | .addLabel('start', 0) 119 | 120 | .fromTo( 121 | this.DOM.deco, 122 | { 123 | yPercent: (pos) => (pos ? -100 : 100), 124 | autoAlpha: 1, 125 | }, 126 | { 127 | yPercent: (pos) => (pos ? -50 : 50), 128 | }, 129 | 'start' 130 | ) 131 | .to( 132 | currentSlide, 133 | { 134 | scale: 1.1, 135 | rotation: direction * 2, 136 | }, 137 | 'start' 138 | ) 139 | 140 | .addLabel('middle', '>') 141 | .add(() => { 142 | // Remove class from the previous slide to unmark it as current 143 | this.DOM.slides[previous].classList.remove('slide--current'); 144 | // Add class to the upcoming slide to mark it as current 145 | this.DOM.slides[this.current].classList.add('slide--current'); 146 | }, 'middle') 147 | .to( 148 | this.DOM.deco, 149 | { 150 | duration: 1.1, 151 | ease: 'expo', 152 | yPercent: (pos) => (pos ? -100 : 100), 153 | }, 154 | 'middle' 155 | ) 156 | 157 | .fromTo( 158 | upcomingSlide, 159 | { 160 | scale: 1.1, 161 | rotation: direction * 2, 162 | }, 163 | { 164 | duration: 1.1, 165 | ease: 'expo', 166 | scale: 1, 167 | rotation: 0, 168 | }, 169 | 'middle' 170 | ); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /js/demo16/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo16/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | 20 | deco: null, // Empty deco element between the slides 21 | }; 22 | /** 23 | * Index of the current slide being displayed. 24 | * @type {number} 25 | */ 26 | current = 0; 27 | /** 28 | * Total number of slides. 29 | * @type {number} 30 | */ 31 | slidesTotal = 0; 32 | 33 | /** 34 | * Flag to indicate if an animation is running. 35 | * @type {boolean} 36 | */ 37 | isAnimating = false; 38 | 39 | /** 40 | * Slideshow constructor. 41 | * Initializes the slideshow and sets up the DOM elements. 42 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 43 | */ 44 | constructor(DOM_el) { 45 | // Initialize DOM elements 46 | this.DOM.el = DOM_el; 47 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 48 | this.DOM.slidesInner = this.DOM.slides.map((item) => 49 | item.querySelector('.slide__img') 50 | ); 51 | 52 | // Set initial slide as current 53 | this.DOM.slides[this.current].classList.add('slide--current'); 54 | 55 | // Count total slides 56 | this.slidesTotal = this.DOM.slides.length; 57 | 58 | // Deco elements 59 | this.DOM.deco = this.DOM.el.querySelectorAll('.deco'); 60 | } 61 | 62 | /** 63 | * Navigate to the next slide. 64 | * @returns {void} 65 | */ 66 | next() { 67 | this.navigate(NEXT); 68 | } 69 | 70 | /** 71 | * Navigate to the previous slide. 72 | * @returns {void} 73 | */ 74 | prev() { 75 | this.navigate(PREV); 76 | } 77 | 78 | /** 79 | * Navigate through slides. 80 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 81 | * @returns {boolean} - Return false if the animation is currently running. 82 | */ 83 | navigate(direction) { 84 | // Check if animation is already running 85 | if (this.isAnimating) return false; 86 | this.isAnimating = true; 87 | 88 | // Update the current slide index based on direction 89 | const previous = this.current; 90 | this.current = 91 | direction === 1 92 | ? this.current < this.slidesTotal - 1 93 | ? ++this.current 94 | : 0 95 | : this.current > 0 96 | ? --this.current 97 | : this.slidesTotal - 1; 98 | 99 | // Get the current and upcoming slides and their inner elements 100 | const currentSlide = this.DOM.slides[previous]; 101 | const currentInner = this.DOM.slidesInner[previous]; 102 | const upcomingSlide = this.DOM.slides[this.current]; 103 | const upcomingInner = this.DOM.slidesInner[this.current]; 104 | 105 | // Animation sequence using GSAP 106 | this.tl = gsap 107 | .timeline({ 108 | defaults: { 109 | duration: 0.8, 110 | ease: 'power4.inOut', 111 | }, 112 | onComplete: () => { 113 | // Reset animation flag 114 | this.isAnimating = false; 115 | }, 116 | }) 117 | // Defining animation steps 118 | .addLabel('start', 0); 119 | 120 | [...this.DOM.deco].forEach((_, pos, arr) => { 121 | const deco = arr[arr.length - 1 - pos]; 122 | this.tl.fromTo( 123 | deco, 124 | { 125 | xPercent: (_) => (pos % 2 === 1 ? -100 : 100), 126 | autoAlpha: 1, 127 | }, 128 | { 129 | xPercent: (_) => (pos % 2 === 1 ? -50 : 50), 130 | onComplete: () => { 131 | if (pos === arr.length - 1) { 132 | // Remove class from the previous slide to unmark it as current 133 | this.DOM.slides[previous].classList.remove('slide--current'); 134 | // Add class to the upcoming slide to mark it as current 135 | this.DOM.slides[this.current].classList.add('slide--current'); 136 | } 137 | }, 138 | }, 139 | `start+=${Math.floor((arr.length - 1 - pos) / 2) * 0.14}` 140 | ); 141 | if (!pos) { 142 | this.tl.addLabel('middle', '>'); 143 | } 144 | }); 145 | 146 | this.tl.to( 147 | currentSlide, 148 | { 149 | ease: 'power4.in', 150 | scale: 0.1, 151 | onComplete: () => gsap.set(currentSlide, { scale: 1 }), 152 | }, 153 | 'start' 154 | ); 155 | 156 | [...this.DOM.deco].forEach((_, pos, arr) => { 157 | const deco = arr[arr.length - 1 - pos]; 158 | 159 | this.tl.to( 160 | deco, 161 | { 162 | xPercent: (_) => (pos % 2 === 1 ? -100 : 100), 163 | }, 164 | `middle+=${Math.floor(pos / 2) * 0.12}` 165 | ); 166 | }); 167 | 168 | this.tl.fromTo( 169 | upcomingSlide, 170 | { 171 | scale: 0.6, 172 | }, 173 | { 174 | duration: 1.1, 175 | ease: 'expo', 176 | scale: 1, 177 | }, 178 | '>-0.8' 179 | ); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /js/demo2/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo2/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | defaults: { 104 | duration: 1.5, 105 | ease: 'power4.inOut', 106 | }, 107 | onStart: () => { 108 | // Add class to the upcoming slide to mark it as current 109 | this.DOM.slides[this.current].classList.add('slide--current'); 110 | }, 111 | onComplete: () => { 112 | // Remove class from the previous slide to unmark it as current 113 | this.DOM.slides[previous].classList.remove('slide--current'); 114 | // Reset animation flag 115 | this.isAnimating = false; 116 | }, 117 | }) 118 | // Defining animation steps 119 | .addLabel('start', 0) 120 | .to( 121 | currentSlide, 122 | { 123 | yPercent: -direction * 100, 124 | }, 125 | 'start' 126 | ) 127 | .to( 128 | currentInner, 129 | { 130 | yPercent: direction * 30, 131 | startAt: { 132 | transformOrigin: direction === NEXT ? '0% 100%' : '100% 0%', 133 | rotation: 0, 134 | }, 135 | rotation: -direction * 10, 136 | scaleY: 2.5, 137 | }, 138 | 'start' 139 | ) 140 | .to( 141 | upcomingSlide, 142 | { 143 | startAt: { 144 | yPercent: direction * 100, 145 | }, 146 | yPercent: 0, 147 | }, 148 | 'start' 149 | ) 150 | .to( 151 | upcomingInner, 152 | { 153 | startAt: { 154 | transformOrigin: direction === NEXT ? '0% 0%' : '100% 100%', 155 | yPercent: -direction * 30, 156 | scaleY: 2.5, 157 | rotation: -direction * 10, 158 | }, 159 | yPercent: 0, 160 | scaleY: 1, 161 | rotation: 0, 162 | }, 163 | 'start' 164 | ); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /js/demo3/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo3/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | defaults: { 104 | duration: 1.1, 105 | ease: 'power2.inOut', 106 | }, 107 | onStart: () => { 108 | // Add class to the upcoming slide to mark it as current 109 | this.DOM.slides[this.current].classList.add('slide--current'); 110 | gsap.set(upcomingSlide, { zIndex: 99 }); 111 | }, 112 | onComplete: () => { 113 | // Remove class from the previous slide to unmark it as current 114 | this.DOM.slides[previous].classList.remove('slide--current'); 115 | gsap.set(upcomingSlide, { zIndex: 1 }); 116 | // Reset animation flag 117 | this.isAnimating = false; 118 | }, 119 | }) 120 | // Defining animation steps 121 | .addLabel('start', 0) 122 | .to( 123 | currentSlide, 124 | { 125 | scale: 0.4, 126 | }, 127 | 'start' 128 | ) 129 | .to( 130 | currentInner, 131 | { 132 | scale: 1.5, 133 | }, 134 | 'start' 135 | ) 136 | .addLabel('middle', 'start+=0.65') 137 | .fromTo( 138 | upcomingSlide, 139 | { 140 | yPercent: direction * 100, 141 | scale: 1, 142 | }, 143 | { 144 | duration: 1, 145 | ease: 'expo', 146 | yPercent: 0, 147 | }, 148 | 'middle' 149 | ) 150 | .fromTo( 151 | upcomingInner, 152 | { 153 | scale: 1.5, 154 | yPercent: -direction * 30, 155 | }, 156 | { 157 | duration: 1.1, 158 | ease: 'expo', 159 | scale: 1, 160 | yPercent: 0, 161 | }, 162 | 'middle' 163 | ); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /js/demo4/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo4/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | defaults: { 104 | duration: 1.25, 105 | ease: 'power4.inOut', 106 | }, 107 | onStart: () => { 108 | // Add class to the upcoming slide to mark it as current 109 | this.DOM.slides[this.current].classList.add('slide--current'); 110 | gsap.set(upcomingSlide, { zIndex: 99 }); 111 | }, 112 | onComplete: () => { 113 | // Remove class from the previous slide to unmark it as current 114 | this.DOM.slides[previous].classList.remove('slide--current'); 115 | gsap.set(upcomingSlide, { zIndex: 1 }); 116 | // Reset animation flag 117 | this.isAnimating = false; 118 | }, 119 | }) 120 | // Defining animation steps 121 | .addLabel('start', 0) 122 | .to( 123 | currentSlide, 124 | { 125 | duration: 0.4, 126 | ease: 'sine', 127 | scale: 0.9, 128 | autoAlpha: 0.2, 129 | }, 130 | 'start' 131 | ) 132 | .to( 133 | currentSlide, 134 | { 135 | yPercent: -direction * 20, 136 | autoAlpha: 0, 137 | }, 138 | 'start+=0.1' 139 | ) 140 | .fromTo( 141 | upcomingSlide, 142 | { 143 | autoAlpha: 1, 144 | scale: 1, 145 | yPercent: direction * 100, 146 | }, 147 | { 148 | yPercent: 0, 149 | }, 150 | 'start+=0.1' 151 | ) 152 | .fromTo( 153 | upcomingInner, 154 | { 155 | yPercent: -direction * 50, 156 | }, 157 | { 158 | yPercent: 0, 159 | }, 160 | 'start+=0.1' 161 | ); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /js/demo5/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo5/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | defaults: { 104 | duration: 1.1, 105 | ease: 'power2.inOut', 106 | }, 107 | onStart: () => { 108 | // Add class to the upcoming slide to mark it as current 109 | this.DOM.slides[this.current].classList.add('slide--current'); 110 | }, 111 | onComplete: () => { 112 | // Remove class from the previous slide to unmark it as current 113 | this.DOM.slides[previous].classList.remove('slide--current'); 114 | // Reset animation flag 115 | this.isAnimating = false; 116 | }, 117 | }) 118 | // Defining animation steps 119 | .addLabel('start', 0) 120 | .to( 121 | currentSlide, 122 | { 123 | scale: 0.6, 124 | yPercent: -direction * 90, 125 | rotation: direction * 20, 126 | autoAlpha: 0, 127 | }, 128 | 'start' 129 | ) 130 | .fromTo( 131 | upcomingSlide, 132 | { 133 | scale: 0.8, 134 | yPercent: direction * 100, 135 | rotation: 0, 136 | autoAlpha: 1, 137 | }, 138 | { 139 | scale: 1, 140 | yPercent: 0, 141 | }, 142 | 'start+=0.1' 143 | ) 144 | .fromTo( 145 | upcomingInner, 146 | { 147 | scale: 1.1, 148 | }, 149 | { 150 | scale: 1, 151 | }, 152 | 'start+=0.1' 153 | ); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /js/demo6/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo6/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | 12 | /** 13 | * Holds references to relevant DOM elements. 14 | * @type {Object} 15 | */ 16 | DOM = { 17 | el: null, // Main slideshow container 18 | slides: null, // Individual slides 19 | slidesInner: null // Inner content of slides (usually images) 20 | }; 21 | /** 22 | * Index of the current slide being displayed. 23 | * @type {number} 24 | */ 25 | current = 0; 26 | /** 27 | * Total number of slides. 28 | * @type {number} 29 | */ 30 | slidesTotal = 0; 31 | 32 | /** 33 | * Flag to indicate if an animation is running. 34 | * @type {boolean} 35 | */ 36 | isAnimating = false; 37 | 38 | /** 39 | * Slideshow constructor. 40 | * Initializes the slideshow and sets up the DOM elements. 41 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 42 | */ 43 | constructor(DOM_el) { 44 | // Initialize DOM elements 45 | this.DOM.el = DOM_el; 46 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 47 | this.DOM.slidesInner = this.DOM.slides.map(item => item.querySelector('.slide__img')); 48 | 49 | // Set initial slide as current 50 | this.DOM.slides[this.current].classList.add('slide--current'); 51 | 52 | // Count total slides 53 | this.slidesTotal = this.DOM.slides.length; 54 | } 55 | 56 | /** 57 | * Navigate to the next slide. 58 | * @returns {void} 59 | */ 60 | next() { 61 | this.navigate(NEXT); 62 | } 63 | 64 | /** 65 | * Navigate to the previous slide. 66 | * @returns {void} 67 | */ 68 | prev() { 69 | this.navigate(PREV); 70 | } 71 | 72 | /** 73 | * Navigate through slides. 74 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 75 | * @returns {boolean} - Return false if the animation is currently running. 76 | */ 77 | navigate(direction) { 78 | // Check if animation is already running 79 | if (this.isAnimating) return false; 80 | this.isAnimating = true; 81 | 82 | // Update the current slide index based on direction 83 | const previous = this.current; 84 | this.current = direction === 1 ? 85 | this.current < this.slidesTotal - 1 ? ++this.current : 0 : 86 | this.current > 0 ? --this.current : this.slidesTotal - 1 87 | 88 | // Get the current and upcoming slides and their inner elements 89 | const currentSlide = this.DOM.slides[previous]; 90 | const currentInner = this.DOM.slidesInner[previous]; 91 | const upcomingSlide = this.DOM.slides[this.current]; 92 | const upcomingInner = this.DOM.slidesInner[this.current]; 93 | 94 | // Animation sequence using GSAP 95 | gsap 96 | .timeline({ 97 | defaults: { 98 | duration: 1.6, 99 | ease: 'power3.inOut' 100 | }, 101 | onStart: () => { 102 | // Add class to the upcoming slide to mark it as current 103 | this.DOM.slides[this.current].classList.add('slide--current'); 104 | }, 105 | onComplete: () => { 106 | // Remove class from the previous slide to unmark it as current 107 | this.DOM.slides[previous].classList.remove('slide--current'); 108 | // Reset animation flag 109 | this.isAnimating = false; 110 | } 111 | }) 112 | // Defining animation steps 113 | .addLabel('start', 0) 114 | .to(currentSlide, { 115 | xPercent: -direction * 100 116 | }, 'start') 117 | .to(currentInner, { 118 | startAt: { transformOrigin: direction === NEXT ? '100% 50%' : '0% 50%' }, 119 | scaleX: 4 120 | }, 'start') 121 | .fromTo(upcomingSlide, { 122 | xPercent: direction * 100 123 | }, { 124 | xPercent: 0 125 | }, 'start') 126 | .fromTo(upcomingInner, { 127 | transformOrigin: direction === NEXT ? '0% 50%' : '100% 50%', 128 | xPercent: -direction * 100, 129 | scaleX: 4 130 | }, { 131 | xPercent: 0, 132 | scaleX: 1 133 | }, 'start'); 134 | } 135 | 136 | } -------------------------------------------------------------------------------- /js/demo7/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo7/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | defaults: { 104 | duration: 1.2, 105 | ease: 'expo', 106 | }, 107 | onStart: () => { 108 | // Add class to the upcoming slide to mark it as current 109 | this.DOM.slides[this.current].classList.add('slide--current'); 110 | gsap.set(upcomingSlide, { zIndex: 99 }); 111 | }, 112 | onComplete: () => { 113 | // Remove class from the previous slide to unmark it as current 114 | this.DOM.slides[previous].classList.remove('slide--current'); 115 | gsap.set(upcomingSlide, { zIndex: 1 }); 116 | // Reset animation flag 117 | this.isAnimating = false; 118 | }, 119 | }) 120 | // Defining animation steps 121 | .addLabel('start', 0) 122 | .to( 123 | currentSlide, 124 | { 125 | ease: 'power2', 126 | autoAlpha: 0, 127 | }, 128 | 'start' 129 | ) 130 | .fromTo( 131 | upcomingSlide, 132 | { 133 | autoAlpha: 1, 134 | scale: 0, 135 | yPercent: direction * 100, 136 | }, 137 | { 138 | scale: 1, 139 | yPercent: 0, 140 | }, 141 | 'start' 142 | ) 143 | .fromTo( 144 | upcomingInner, 145 | { 146 | scale: 2, 147 | filter: 'brightness(600%)', 148 | }, 149 | { 150 | scale: 1, 151 | filter: 'brightness(100%)', 152 | }, 153 | 'start' 154 | ); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /js/demo8/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo8/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | onStart: () => { 104 | // Add class to the upcoming slide to mark it as current 105 | this.DOM.slides[this.current].classList.add('slide--current'); 106 | gsap.set(upcomingSlide, { zIndex: 99 }); 107 | }, 108 | onComplete: () => { 109 | // Remove class from the previous slide to unmark it as current 110 | this.DOM.slides[previous].classList.remove('slide--current'); 111 | gsap.set(upcomingSlide, { zIndex: 1 }); 112 | // Reset animation flag 113 | this.isAnimating = false; 114 | }, 115 | }) 116 | // Defining animation steps 117 | .addLabel('start', 0) 118 | .fromTo( 119 | upcomingSlide, 120 | { 121 | autoAlpha: 1, 122 | scale: 0.1, 123 | xPercent: direction * 100, 124 | }, 125 | { 126 | duration: 0.7, 127 | ease: 'expo', 128 | scale: 0.4, 129 | xPercent: 0, 130 | }, 131 | 'start' 132 | ) 133 | .fromTo( 134 | upcomingInner, 135 | { 136 | filter: 'contrast(100%) saturate(100%)', 137 | transformOrigin: '100% 50%', 138 | scaleX: 4, 139 | }, 140 | { 141 | duration: 0.7, 142 | ease: 'expo', 143 | scaleX: 1, 144 | }, 145 | 'start' 146 | ) 147 | .fromTo( 148 | currentInner, 149 | { 150 | filter: 'contrast(100%) saturate(100%)', 151 | }, 152 | { 153 | duration: 0.7, 154 | ease: 'expo', 155 | filter: 'contrast(120%) saturate(140%)', 156 | }, 157 | 'start' 158 | ) 159 | 160 | .addLabel('middle', 'start+=0.6') 161 | .to( 162 | upcomingSlide, 163 | { 164 | duration: 1, 165 | ease: 'power4.inOut', 166 | scale: 1, 167 | }, 168 | 'middle' 169 | ) 170 | .to( 171 | currentSlide, 172 | { 173 | duration: 1, 174 | ease: 'power4.inOut', 175 | scale: 0.98, 176 | autoAlpha: 0, 177 | }, 178 | 'middle' 179 | ); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /js/demo9/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages } from '../utils.js'; // Utility function to preload images 2 | import { Slideshow } from './slideshow.js'; 3 | 4 | const slides = document.querySelector('.slides'); 5 | const slideshow = new Slideshow(slides); 6 | 7 | document 8 | .querySelector('.slides-nav__item--prev') 9 | .addEventListener('click', () => slideshow.prev()); 10 | document 11 | .querySelector('.slides-nav__item--next') 12 | .addEventListener('click', () => slideshow.next()); 13 | // Initialize the GSAP Observer plugin 14 | Observer.create({ 15 | type: 'wheel,touch,pointer', 16 | onDown: () => slideshow.prev(), 17 | onUp: () => slideshow.next(), 18 | // invert the mouse wheel delta 19 | wheelSpeed: -1, 20 | tolerance: 10, 21 | }); 22 | 23 | // Preload all images. Once all images are preloaded, remove the 'loading' class from the body. 24 | preloadImages('.slide__img').then(() => 25 | document.body.classList.remove('loading') 26 | ); 27 | -------------------------------------------------------------------------------- /js/demo9/slideshow.js: -------------------------------------------------------------------------------- 1 | /** Direction constants */ 2 | const NEXT = 1; 3 | const PREV = -1; 4 | 5 | /** 6 | * Slideshow Class 7 | * Manages slideshow functionality including navigation and animations. 8 | * @export 9 | */ 10 | export class Slideshow { 11 | /** 12 | * Holds references to relevant DOM elements. 13 | * @type {Object} 14 | */ 15 | DOM = { 16 | el: null, // Main slideshow container 17 | slides: null, // Individual slides 18 | slidesInner: null, // Inner content of slides (usually images) 19 | }; 20 | /** 21 | * Index of the current slide being displayed. 22 | * @type {number} 23 | */ 24 | current = 0; 25 | /** 26 | * Total number of slides. 27 | * @type {number} 28 | */ 29 | slidesTotal = 0; 30 | 31 | /** 32 | * Flag to indicate if an animation is running. 33 | * @type {boolean} 34 | */ 35 | isAnimating = false; 36 | 37 | /** 38 | * Slideshow constructor. 39 | * Initializes the slideshow and sets up the DOM elements. 40 | * @param {HTMLElement} DOM_el - The main element holding all the slides. 41 | */ 42 | constructor(DOM_el) { 43 | // Initialize DOM elements 44 | this.DOM.el = DOM_el; 45 | this.DOM.slides = [...this.DOM.el.querySelectorAll('.slide')]; 46 | this.DOM.slidesInner = this.DOM.slides.map((item) => 47 | item.querySelector('.slide__img') 48 | ); 49 | 50 | // Set initial slide as current 51 | this.DOM.slides[this.current].classList.add('slide--current'); 52 | 53 | // Count total slides 54 | this.slidesTotal = this.DOM.slides.length; 55 | } 56 | 57 | /** 58 | * Navigate to the next slide. 59 | * @returns {void} 60 | */ 61 | next() { 62 | this.navigate(NEXT); 63 | } 64 | 65 | /** 66 | * Navigate to the previous slide. 67 | * @returns {void} 68 | */ 69 | prev() { 70 | this.navigate(PREV); 71 | } 72 | 73 | /** 74 | * Navigate through slides. 75 | * @param {number} direction - The direction to navigate. 1 for next and -1 for previous. 76 | * @returns {boolean} - Return false if the animation is currently running. 77 | */ 78 | navigate(direction) { 79 | // Check if animation is already running 80 | if (this.isAnimating) return false; 81 | this.isAnimating = true; 82 | 83 | // Update the current slide index based on direction 84 | const previous = this.current; 85 | this.current = 86 | direction === 1 87 | ? this.current < this.slidesTotal - 1 88 | ? ++this.current 89 | : 0 90 | : this.current > 0 91 | ? --this.current 92 | : this.slidesTotal - 1; 93 | 94 | // Get the current and upcoming slides and their inner elements 95 | const currentSlide = this.DOM.slides[previous]; 96 | const currentInner = this.DOM.slidesInner[previous]; 97 | const upcomingSlide = this.DOM.slides[this.current]; 98 | const upcomingInner = this.DOM.slidesInner[this.current]; 99 | 100 | // Animation sequence using GSAP 101 | gsap 102 | .timeline({ 103 | defaults: { 104 | duration: 1.2, 105 | ease: 'expo', 106 | }, 107 | onStart: () => { 108 | // Add class to the upcoming slide to mark it as current 109 | this.DOM.slides[this.current].classList.add('slide--current'); 110 | gsap.set(upcomingSlide, { zIndex: 99 }); 111 | }, 112 | onComplete: () => { 113 | // Remove class from the previous slide to unmark it as current 114 | this.DOM.slides[previous].classList.remove('slide--current'); 115 | gsap.set(upcomingSlide, { zIndex: 1 }); 116 | // Reset animation flag 117 | this.isAnimating = false; 118 | }, 119 | }) 120 | // Defining animation steps 121 | .addLabel('start', 0) 122 | .to( 123 | currentSlide, 124 | { 125 | duration: 1, 126 | ease: 'power4', 127 | rotation: 500, 128 | scale: 0, 129 | xPercent: -20, 130 | onComplete: () => 131 | gsap.set(currentSlide, { 132 | rotation: 0, 133 | scale: 1, 134 | autoAlpha: 0, 135 | }), 136 | }, 137 | 'start' 138 | ) 139 | .fromTo( 140 | upcomingSlide, 141 | { 142 | autoAlpha: 0, 143 | scale: 1.4, 144 | rotation: -90, 145 | xPercent: 20, 146 | }, 147 | { 148 | duration: 0.6, 149 | ease: 'power4', 150 | autoAlpha: 1, 151 | scale: 1, 152 | rotation: 0, 153 | xPercent: 0, 154 | }, 155 | 'start+=0.3' 156 | ); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /js/imagesloaded.pkgd.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * imagesLoaded PACKAGED v5.0.0 3 | * JavaScript is all like "You images are done yet or what?" 4 | * MIT License 5 | */ 6 | !function(t,e){"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,(function(){function t(){}let e=t.prototype;return e.on=function(t,e){if(!t||!e)return this;let i=this._events=this._events||{},s=i[t]=i[t]||[];return s.includes(e)||s.push(e),this},e.once=function(t,e){if(!t||!e)return this;this.on(t,e);let i=this._onceEvents=this._onceEvents||{};return(i[t]=i[t]||{})[e]=!0,this},e.off=function(t,e){let i=this._events&&this._events[t];if(!i||!i.length)return this;let s=i.indexOf(e);return-1!=s&&i.splice(s,1),this},e.emitEvent=function(t,e){let i=this._events&&this._events[t];if(!i||!i.length)return this;i=i.slice(0),e=e||[];let s=this._onceEvents&&this._onceEvents[t];for(let n of i){s&&s[n]&&(this.off(t,n),delete s[n]),n.apply(this,e)}return this},e.allOff=function(){return delete this._events,delete this._onceEvents,this},t})), 7 | /*! 8 | * imagesLoaded v5.0.0 9 | * JavaScript is all like "You images are done yet or what?" 10 | * MIT License 11 | */ 12 | function(t,e){"object"==typeof module&&module.exports?module.exports=e(t,require("ev-emitter")):t.imagesLoaded=e(t,t.EvEmitter)}("undefined"!=typeof window?window:this,(function(t,e){let i=t.jQuery,s=t.console;function n(t,e,o){if(!(this instanceof n))return new n(t,e,o);let r=t;var h;("string"==typeof t&&(r=document.querySelectorAll(t)),r)?(this.elements=(h=r,Array.isArray(h)?h:"object"==typeof h&&"number"==typeof h.length?[...h]:[h]),this.options={},"function"==typeof e?o=e:Object.assign(this.options,e),o&&this.on("always",o),this.getImages(),i&&(this.jqDeferred=new i.Deferred),setTimeout(this.check.bind(this))):s.error(`Bad element for imagesLoaded ${r||t}`)}n.prototype=Object.create(e.prototype),n.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)};const o=[1,9,11];n.prototype.addElementImages=function(t){"IMG"===t.nodeName&&this.addImage(t),!0===this.options.background&&this.addElementBackgroundImages(t);let{nodeType:e}=t;if(!e||!o.includes(e))return;let i=t.querySelectorAll("img");for(let t of i)this.addImage(t);if("string"==typeof this.options.background){let e=t.querySelectorAll(this.options.background);for(let t of e)this.addElementBackgroundImages(t)}};const r=/url\((['"])?(.*?)\1\)/gi;function h(t){this.img=t}function d(t,e){this.url=t,this.element=e,this.img=new Image}return n.prototype.addElementBackgroundImages=function(t){let e=getComputedStyle(t);if(!e)return;let i=r.exec(e.backgroundImage);for(;null!==i;){let s=i&&i[2];s&&this.addBackground(s,t),i=r.exec(e.backgroundImage)}},n.prototype.addImage=function(t){let e=new h(t);this.images.push(e)},n.prototype.addBackground=function(t,e){let i=new d(t,e);this.images.push(i)},n.prototype.check=function(){if(this.progressedCount=0,this.hasAnyBroken=!1,!this.images.length)return void this.complete();let t=(t,e,i)=>{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/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Preload images function 3 | * @param {string} selector - The CSS selector for the images to be preloaded. Default is 'img'. 4 | * @returns {Promise} A promise that resolves when all the images are loaded. 5 | */ 6 | const preloadImages = (selector = 'img') => { 7 | return new Promise((resolve) => { 8 | // Use the imagesLoaded library to ensure all images are fully loaded. 9 | imagesLoaded(document.querySelectorAll(selector), {background: true}, resolve); 10 | }); 11 | }; 12 | 13 | export { 14 | preloadImages, 15 | }; 16 | --------------------------------------------------------------------------------