├── .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 | 
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
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 |
94 |
100 |
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 |
94 |
100 |
106 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
94 |
100 |
106 |
112 |
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 |
95 |
96 |
102 |
108 |
114 |
120 |
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 |
--------------------------------------------------------------------------------