├── .gitattributes ├── LICENSE ├── README.md ├── css └── base.css ├── favicon.ico ├── img ├── 1.jpg ├── 10.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg ├── 7.jpg ├── 8.jpg └── 9.jpg ├── index.html ├── index2.html ├── index3.html ├── index4.html ├── index5.html ├── index6.html └── js ├── demo1 ├── index.js └── overlay.js ├── demo2 ├── index.js └── overlay.js ├── demo3 ├── index.js └── overlay.js ├── demo4 ├── index.js └── overlay.js ├── demo5 ├── index.js └── overlay.js ├── demo6 ├── index.js └── overlay.js └── utils.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2009 - 2023 [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 | # Pixel Transition Effects 2 | 3 | Ideas for pixel page transitions based on an [animation](https://twitter.com/niccolomiranda/status/1628359949972819968) by [Niccolò Miranda](https://www.instagram.com/niccolomiranda/). 4 | 5 | ![Pixel Transition](https://tympanus.net/codrops/wp-content/uploads/2023/04/pixeltransition.jpg) 6 | 7 | [Article on Codrops](https://tympanus.net/codrops/?p=71437) 8 | 9 | [Demo](http://tympanus.net/Development/PixelTransition/) 10 | 11 | 12 | ## Installation 13 | 14 | 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). 15 | 16 | ## Credits 17 | 18 | - Images from [Pexels](https://www.pexels.com/) 19 | 20 | ## Misc 21 | 22 | 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/) 23 | 24 | ## License 25 | [MIT](LICENSE) 26 | 27 | Made with :blue_heart: by [Codrops](http://www.codrops.com) 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 12px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | overflow: hidden; 14 | --color-text: #fff; 15 | --color-gr-1: #4cfa68; 16 | --color-gr-2: #1b35ea; 17 | --color-bg: #272f2e; 18 | --color-link: #6d91c9; 19 | --color-link-hover: #60c18d; 20 | --padding-ver: 1.5rem; 21 | --padding-hor: 1.5rem; 22 | --color-bg-overlay: #000; 23 | --color-back: #6d91c9; 24 | --color-back-hover: #60c18d; 25 | color: var(--color-text); 26 | background-color: var(--color-bg); 27 | font-family: area-normal, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 28 | -webkit-font-smoothing: antialiased; 29 | -moz-osx-font-smoothing: grayscale; 30 | } 31 | 32 | .demo-2 { 33 | --color-text: #000; 34 | --color-gr-1: #81e2c6; 35 | --color-gr-2: #e7613c; 36 | --color-bg: #f9f9f9; 37 | --color-link: #d23636; 38 | --color-link-hover: #df6b47; 39 | --color-back: #d23636; 40 | --color-back-hover: #df6b47; 41 | --color-bg-overlay: rgb(37, 116, 66); 42 | } 43 | 44 | .demo-3 { 45 | --color-text: #fff; 46 | --color-gr-1: #81e2c6; 47 | --color-gr-2: #e7613c; 48 | --color-bg: #000; 49 | --color-link: #ba9978; 50 | --color-link-hover: #df6b47; 51 | --color-back: #d23636; 52 | --color-back-hover: #df6b47; 53 | --color-bg-overlay: rgb(223, 107, 71); 54 | } 55 | 56 | .demo-4 { 57 | --color-text: #000; 58 | --color-gr-1: #97d6c5; 59 | --color-gr-2: #308c2c; 60 | --color-bg: #4b7872; 61 | --color-link: #1cf191; 62 | --color-link-hover: #97d6c5; 63 | --color-back: #1cf191; 64 | --color-back-hover: #97d6c5; 65 | } 66 | 67 | .demo-5 { 68 | --color-text: #000; 69 | --color-gr-1: #c4b478; 70 | --color-gr-2: #815615; 71 | --color-bg: #394235; 72 | --color-link: #c4b478; 73 | --color-link-hover: #957235; 74 | --color-back: #c4b478; 75 | --color-back-hover: #957235; 76 | --color-bg-overlay: rgb(20 21 19); 77 | } 78 | 79 | .demo-6 { 80 | --color-text: #000; 81 | --color-gr-1: #000; 82 | --color-gr-2: #000; 83 | --color-bg: #7f837f; 84 | --color-link: #c0c8c2; 85 | --color-link-hover: #000; 86 | --color-back: #c0c8c2; 87 | --color-back-hover: #000; 88 | --color-bg-overlay: rgb(84 87 84); 89 | } 90 | 91 | /* Page Loader */ 92 | .js .loading::before, 93 | .js .loading::after { 94 | content: ''; 95 | position: fixed; 96 | z-index: 1000; 97 | } 98 | 99 | .js .loading::before { 100 | top: 0; 101 | left: 0; 102 | width: 100%; 103 | height: 100%; 104 | background: var(--color-bg); 105 | } 106 | 107 | .js .loading::after { 108 | top: 50%; 109 | left: 50%; 110 | width: 100px; 111 | height: 100px; 112 | margin: -50px 0 0 -50px; 113 | border-radius: 50%; 114 | border: 2px solid var(--color-gr-2); 115 | animation: loaderAnim 0.7s linear infinite alternate forwards; 116 | 117 | } 118 | 119 | @keyframes loaderAnim { 120 | to { 121 | opacity: 1; 122 | transform: scale3d(0.5,0.5,1); 123 | } 124 | } 125 | 126 | a { 127 | text-decoration: none; 128 | color: var(--color-link); 129 | outline: none; 130 | } 131 | 132 | a:hover { 133 | color: var(--color-link-hover); 134 | outline: none; 135 | } 136 | 137 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 138 | a:focus { 139 | /* Provide a fallback style for browsers 140 | that don't support :focus-visible */ 141 | outline: none; 142 | background: lightgrey; 143 | } 144 | 145 | a:focus:not(:focus-visible) { 146 | /* Remove the focus indicator on mouse-focus for browsers 147 | that do support :focus-visible */ 148 | background: transparent; 149 | } 150 | 151 | a:focus-visible { 152 | /* Draw a very noticeable focus style for 153 | keyboard-focus on browsers that do support 154 | :focus-visible */ 155 | outline: 2px solid red; 156 | background: transparent; 157 | } 158 | 159 | .hover-line, 160 | a.cda-sponsor-link { 161 | white-space: nowrap; 162 | overflow: hidden; 163 | position: relative; 164 | } 165 | 166 | .hover-line::before, 167 | .cda-sponsor-link::before { 168 | content: ''; 169 | height: 1px; 170 | width: 100%; 171 | background: currentColor; 172 | position: absolute; 173 | top: 92%; 174 | transition: transform 0.3s; 175 | transform-origin: 0% 50%; 176 | } 177 | 178 | .hover-line:hover::before, 179 | .cda-sponsor-link:hover::before { 180 | transform: scaleX(0); 181 | transform-origin: 100% 50%; 182 | } 183 | 184 | .unbutton { 185 | background: none; 186 | border: 0; 187 | padding: 0; 188 | margin: 0; 189 | font: inherit; 190 | cursor: pointer; 191 | } 192 | 193 | .unbutton:focus { 194 | outline: none; 195 | } 196 | 197 | .hidden { 198 | opacity: 0; 199 | pointer-events: none; 200 | position: absolute; 201 | } 202 | 203 | main { 204 | display: grid; 205 | height: 100vh; 206 | padding: 0; 207 | position: relative; 208 | } 209 | 210 | .frame { 211 | grid-area: 1 / 1 / 2 / 2; 212 | text-align: center; 213 | display: flex; 214 | padding: var(--padding-hor) calc(var(--padding-ver) + 0.6vw); 215 | flex-wrap: wrap; 216 | align-self: start; 217 | position: relative; 218 | z-index: 100; 219 | grid-column-gap: 5vw; 220 | grid-row-gap: 1rem; 221 | font-weight: 600; 222 | background: linear-gradient(to bottom, var(--color-bg), transparent); 223 | } 224 | 225 | .frame__title { 226 | font-size: inherit; 227 | margin: 0; 228 | font-weight: inherit; 229 | } 230 | 231 | .frame__links { 232 | display: flex; 233 | gap: 1rem; 234 | } 235 | 236 | .frame__demos { 237 | display: flex; 238 | gap: 1rem; 239 | } 240 | 241 | .intro, 242 | .content-wrap { 243 | position: relative; 244 | grid-area: 1 / 1 / 2 / 2; 245 | } 246 | 247 | .intro { 248 | flex: 1; 249 | max-height: 80vmax; 250 | margin: auto 0; 251 | padding: 0 var(--padding-ver); 252 | font-size: 9vw; 253 | line-height: 1; 254 | text-transform: uppercase; 255 | display: flex; 256 | flex-wrap: wrap; 257 | column-gap: 2vw; 258 | row-gap: 1vw; 259 | white-space: nowrap; 260 | font-family: "stinger-variable", sans-serif; 261 | font-variation-settings: "wdth" 120, "wght" 300; 262 | background-color: var(--color-text); 263 | background-image: linear-gradient(45deg, var(--color-gr-1), var(--color-gr-2)); 264 | background-size: 100%; 265 | background-repeat: repeat; 266 | -webkit-background-clip: text; 267 | -webkit-text-fill-color: transparent; 268 | -moz-background-clip: text; 269 | -moz-text-fill-color: transparent; 270 | will-change: transform, opacity; 271 | } 272 | 273 | .intro--closed { 274 | opacity: 0; 275 | pointer-events: none; 276 | } 277 | 278 | .font-1 { 279 | font-variation-settings: "wdth" 75, "wght" 100; 280 | } 281 | 282 | .font-2 { 283 | font-variation-settings: "wdth" 120, "wght" 800; 284 | } 285 | 286 | .font-3 { 287 | font-variation-settings: "wdth" 120, "wght" 400; 288 | } 289 | 290 | .intro__text { 291 | line-height: 0.6; 292 | padding-top: 2vw; 293 | } 294 | 295 | .intro__image { 296 | flex: 1; 297 | position: relative; 298 | cursor: pointer; 299 | will-change: transform; 300 | background-size: cover; 301 | background-position: 50% 30%; 302 | border-radius: 5vw; 303 | min-width: 50px; 304 | max-width: 100px; 305 | transition: opacity 0.3s; 306 | } 307 | 308 | .intro__image:hover { 309 | opacity: 0.8; 310 | } 311 | 312 | .content-wrap { 313 | align-self: stretch; 314 | display: grid; 315 | pointer-events: none; 316 | } 317 | 318 | .content { 319 | opacity: 0; 320 | pointer-events: none; 321 | grid-area: 1 / 1 / -1 / -1; 322 | display: grid; 323 | grid-template-columns: 100%; 324 | height: 100%; 325 | grid-template-rows: 70% 1fr; 326 | gap: 5vh; 327 | padding: 8rem var(--padding-ver) 2rem; 328 | } 329 | 330 | .content--open { 331 | opacity: 1; 332 | pointer-events: auto; 333 | } 334 | 335 | .content__img { 336 | position: relative; 337 | overflow: hidden; 338 | border-radius: 1.85rem; 339 | display: grid; 340 | will-change: transform, opacity; 341 | } 342 | 343 | .content__img-inner { 344 | background-size: cover; 345 | background-position: 50% 20%; 346 | } 347 | 348 | .content__text { 349 | display: grid; 350 | grid-template-areas: 351 | 'back number title' 352 | '... ... title' 353 | 'meta meta meta'; 354 | grid-column-gap: 2rem; 355 | grid-template-columns: auto 1fr auto; 356 | grid-template-rows: auto 1fr auto; 357 | } 358 | 359 | .content__title { 360 | font-variation-settings: "wdth" 120, "wght" 100; 361 | grid-area: title; 362 | margin: 0; 363 | font-family: stinger-variable, sans-serif; 364 | font-size: clamp(2rem, 6vw, 5rem); 365 | background-color: var(--color-text); 366 | background-image: linear-gradient(45deg, var(--color-gr-1), var(--color-gr-2)); 367 | background-size: 100%; 368 | background-repeat: repeat; 369 | -webkit-background-clip: text; 370 | -webkit-text-fill-color: transparent; 371 | -moz-background-clip: text; 372 | -moz-text-fill-color: transparent; 373 | line-height: 1; 374 | max-width: 15ch; 375 | text-align: right; 376 | } 377 | 378 | .content__number { 379 | grid-area: number; 380 | line-height: 1; 381 | margin-top: -1vw; 382 | align-self: start; 383 | font-size: clamp(3rem, 6vw, 10rem); 384 | background-color: var(--color-text); 385 | background-image: linear-gradient(45deg, var(--color-gr-1), var(--color-gr-2)); 386 | background-size: 100%; 387 | background-repeat: repeat; 388 | -webkit-background-clip: text; 389 | -webkit-text-fill-color: transparent; 390 | -moz-background-clip: text; 391 | -moz-text-fill-color: transparent; 392 | position: relative; 393 | } 394 | 395 | .content__back { 396 | grid-area: back; 397 | overflow: hidden; 398 | align-self: center; 399 | } 400 | 401 | .content__back svg { 402 | width: 4vw; 403 | height: 4.85vw; 404 | fill: var(--color-back); 405 | transition: fill 0.2s; 406 | } 407 | 408 | .content__back:hover svg { 409 | fill: var(--color-back-hover); 410 | } 411 | 412 | .content__meta { 413 | grid-area: meta; 414 | text-transform: uppercase; 415 | display: flex; 416 | justify-content: space-between; 417 | font-size: clamp(0.75rem, 3vw, 1.5rem); 418 | line-height: 1; 419 | } 420 | 421 | .overlay { 422 | grid-area: 1 / 1 / -1 / -1; 423 | display: grid; 424 | position: relative; 425 | z-index: 1000; 426 | pointer-events: none; 427 | opacity: 0; 428 | --columns: 20; 429 | grid-template-columns: repeat(var(--columns),1fr); 430 | } 431 | 432 | .overlay div { 433 | background: var(--color-bg-overlay); 434 | } 435 | 436 | @media screen and (min-width: 53em) { 437 | .intro__image { 438 | min-width: 200px; 439 | max-width: 30%; 440 | } 441 | .content { 442 | padding-top: 5rem; 443 | } 444 | } 445 | 446 | 447 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/favicon.ico -------------------------------------------------------------------------------- /img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/1.jpg -------------------------------------------------------------------------------- /img/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/10.jpg -------------------------------------------------------------------------------- /img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/2.jpg -------------------------------------------------------------------------------- /img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/3.jpg -------------------------------------------------------------------------------- /img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/4.jpg -------------------------------------------------------------------------------- /img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/5.jpg -------------------------------------------------------------------------------- /img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/6.jpg -------------------------------------------------------------------------------- /img/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/7.jpg -------------------------------------------------------------------------------- /img/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/8.jpg -------------------------------------------------------------------------------- /img/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/PixelTransition/2651c9d5dc53d895cb7b3d721ddb9bdb1669f9ba/img/9.jpg -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pixel Transition | Demo 1 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 |
24 |
25 |

Pixel Transition

26 | 30 | 39 |
40 |
41 |
Rather
42 |
43 |
than
44 |
45 |
love
46 |
47 |
than
48 |
49 |
money
50 |
51 |
than
52 |
53 |
fame
54 |
55 |
give
56 |
me
57 |
58 |
truth
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |

Guard your time and attention.

68 | M36 69 | 74 | 79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |

Seek simplicity and nature.

87 | B13 88 | 93 | 98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |

Avoid accumulating needless things.

106 | G98 107 | 112 | 117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |

Be conscious of the stories you tell.

125 | K06 126 | 131 | 136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |

Rest, reflect, and play.

144 | W02 145 | 150 | 155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |

Your actions have consequences.

163 | T67 164 | 169 | 174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |

Don't compromise your integrity.

182 | X49 183 | 188 | 193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |

Seek greater wisdom and compassion.

201 | G05 202 | 207 | 212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |

Value experiences over material possessions.

220 | K16 221 | 226 | 231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |

Live a life of purpose.

239 | Z09 240 | 245 | 250 |
251 |
252 |
253 |
254 |
255 | 256 | 257 | 258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pixel Transition | Demo 2 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 |
24 |
25 |

Pixel Transition

26 | 30 | 39 |
40 |
41 |
Rather
42 |
43 |
than
44 |
45 |
love
46 |
47 |
than
48 |
49 |
money
50 |
51 |
than
52 |
53 |
fame
54 |
55 |
give
56 |
me
57 |
58 |
truth
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |

Guard your time and attention.

68 | M36 69 | 74 | 79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |

Seek simplicity and nature.

87 | B13 88 | 93 | 98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |

Avoid accumulating needless things.

106 | G98 107 | 112 | 117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |

Be conscious of the stories you tell.

125 | K06 126 | 131 | 136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |

Rest, reflect, and play.

144 | W02 145 | 150 | 155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |

Your actions have consequences.

163 | T67 164 | 169 | 174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |

Don't compromise your integrity.

182 | X49 183 | 188 | 193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |

Seek greater wisdom and compassion.

201 | G05 202 | 207 | 212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |

Value experiences over material possessions.

220 | K16 221 | 226 | 231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |

Live a life of purpose.

239 | Z09 240 | 245 | 250 |
251 |
252 |
253 |
254 |
255 | 256 | 257 | 258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /index3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pixel Transition | Demo 3 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 |
24 |
25 |

Pixel Transition

26 | 30 | 39 |
40 |
41 |
Rather
42 |
43 |
than
44 |
45 |
love
46 |
47 |
than
48 |
49 |
money
50 |
51 |
than
52 |
53 |
fame
54 |
55 |
give
56 |
me
57 |
58 |
truth
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |

Guard your time and attention.

68 | M36 69 | 74 | 79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |

Seek simplicity and nature.

87 | B13 88 | 93 | 98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |

Avoid accumulating needless things.

106 | G98 107 | 112 | 117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |

Be conscious of the stories you tell.

125 | K06 126 | 131 | 136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |

Rest, reflect, and play.

144 | W02 145 | 150 | 155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |

Your actions have consequences.

163 | T67 164 | 169 | 174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |

Don't compromise your integrity.

182 | X49 183 | 188 | 193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |

Seek greater wisdom and compassion.

201 | G05 202 | 207 | 212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |

Value experiences over material possessions.

220 | K16 221 | 226 | 231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |

Live a life of purpose.

239 | Z09 240 | 245 | 250 |
251 |
252 |
253 |
254 |
255 | 256 | 257 | 258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /index4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pixel Transition | Demo 2 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 |
24 |
25 |

Pixel Transition

26 | 30 | 39 |
40 |
41 |
Rather
42 |
43 |
than
44 |
45 |
love
46 |
47 |
than
48 |
49 |
money
50 |
51 |
than
52 |
53 |
fame
54 |
55 |
give
56 |
me
57 |
58 |
truth
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |

Guard your time and attention.

68 | M36 69 | 74 | 79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |

Seek simplicity and nature.

87 | B13 88 | 93 | 98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |

Avoid accumulating needless things.

106 | G98 107 | 112 | 117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |

Be conscious of the stories you tell.

125 | K06 126 | 131 | 136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |

Rest, reflect, and play.

144 | W02 145 | 150 | 155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |

Your actions have consequences.

163 | T67 164 | 169 | 174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |

Don't compromise your integrity.

182 | X49 183 | 188 | 193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |

Seek greater wisdom and compassion.

201 | G05 202 | 207 | 212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |

Value experiences over material possessions.

220 | K16 221 | 226 | 231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |

Live a life of purpose.

239 | Z09 240 | 245 | 250 |
251 |
252 |
253 |
254 |
255 | 256 | 257 | 258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /index5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pixel Transition | Demo 5 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 |
24 |
25 |

Pixel Transition

26 | 30 | 39 |
40 |
41 |
Rather
42 |
43 |
than
44 |
45 |
love
46 |
47 |
than
48 |
49 |
money
50 |
51 |
than
52 |
53 |
fame
54 |
55 |
give
56 |
me
57 |
58 |
truth
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |

Guard your time and attention.

68 | M36 69 | 74 | 79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |

Seek simplicity and nature.

87 | B13 88 | 93 | 98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |

Avoid accumulating needless things.

106 | G98 107 | 112 | 117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |

Be conscious of the stories you tell.

125 | K06 126 | 131 | 136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |

Rest, reflect, and play.

144 | W02 145 | 150 | 155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |

Your actions have consequences.

163 | T67 164 | 169 | 174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |

Don't compromise your integrity.

182 | X49 183 | 188 | 193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |

Seek greater wisdom and compassion.

201 | G05 202 | 207 | 212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |

Value experiences over material possessions.

220 | K16 221 | 226 | 231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |

Live a life of purpose.

239 | Z09 240 | 245 | 250 |
251 |
252 |
253 |
254 |
255 | 256 | 257 | 258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /index6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pixel Transition | Demo 6 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 |
24 |
25 |

Pixel Transition

26 | 30 | 39 |
40 |
41 |
Rather
42 |
43 |
than
44 |
45 |
love
46 |
47 |
than
48 |
49 |
money
50 |
51 |
than
52 |
53 |
fame
54 |
55 |
give
56 |
me
57 |
58 |
truth
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |

Guard your time and attention.

68 | M36 69 | 74 | 79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |

Seek simplicity and nature.

87 | B13 88 | 93 | 98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |

Avoid accumulating needless things.

106 | G98 107 | 112 | 117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |

Be conscious of the stories you tell.

125 | K06 126 | 131 | 136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |

Rest, reflect, and play.

144 | W02 145 | 150 | 155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |

Your actions have consequences.

163 | T67 164 | 169 | 174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |

Don't compromise your integrity.

182 | X49 183 | 188 | 193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |

Seek greater wisdom and compassion.

201 | G05 202 | 207 | 212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |

Value experiences over material possessions.

220 | K16 221 | 226 | 231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |

Live a life of purpose.

239 | Z09 240 | 245 | 250 |
251 |
252 |
253 |
254 |
255 | 256 | 257 | 258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /js/demo1/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages, preloadFonts } from '../utils.js'; 2 | import { Overlay } from './overlay.js'; 3 | 4 | // Select the overlay element from the DOM 5 | const overlayEl = document.querySelector('.overlay'); 6 | 7 | // Intro 8 | const intro = document.querySelector('.intro'); 9 | 10 | // Intro images 11 | const images = [...intro.querySelectorAll('.intro__image')]; 12 | 13 | // Content elements 14 | const contentElements = [...document.querySelectorAll('.content-wrap > .content')]; 15 | 16 | // Instantiate an Overlay object using the selected overlay element 17 | const overlay = new Overlay(overlayEl, { 18 | rows: 8, 19 | columns: 14 20 | }); 21 | 22 | let isAnimating = false; 23 | 24 | // Attach click event listeners to each intro image 25 | images.forEach((image, position) => { 26 | // Show the overlay when an intro image is clicked 27 | image.addEventListener('click', () => { 28 | if ( isAnimating ) return; 29 | isAnimating = true; 30 | 31 | // Animate intro section 32 | gsap.to(intro, { 33 | duration: 0.8, 34 | ease: 'power3.inOut', 35 | yPercent: 15, 36 | opacity: 0 37 | }); 38 | 39 | overlay.show({ 40 | // Specify the cell's transform origin 41 | transformOrigin: '50% 0%', 42 | // Duration for each cell animation 43 | duration: 0.4, 44 | // Ease for each cell animation 45 | ease: 'power3.inOut', 46 | // Stagger function 47 | stagger: index => 0.03 * (overlay.cells.flat()[index].row + gsap.utils.random(0,5)) 48 | }) 49 | .then(() => { 50 | // show content 51 | intro.classList.add('intro--closed'); 52 | contentElements[position].classList.add('content--open'); 53 | 54 | // Now hide the overlay 55 | overlay.hide({ 56 | // Specify the cell's transform origin 57 | transformOrigin: '50% 100%', 58 | // Duration for each cell animation 59 | duration: 0.4, 60 | // Ease for each cell animation 61 | ease: 'power2', 62 | // Stagger function 63 | stagger: index => 0.03 * (overlay.cells.flat()[index].row + gsap.utils.random(0,5)) 64 | }).then(() => isAnimating = false); 65 | 66 | // Animate content image 67 | gsap.fromTo(contentElements[position].querySelector('.content__img'), { 68 | yPercent: -25, 69 | opacity: 0 70 | }, { 71 | duration: 0.8, 72 | ease: 'power3', 73 | yPercent: 0, 74 | opacity: 1 75 | }); 76 | }) 77 | 78 | }); 79 | }); 80 | 81 | // Attach click event listeners to each content back button 82 | contentElements.forEach((content, position) => { 83 | content.querySelector('.content__back').addEventListener('click', () => { 84 | if ( isAnimating ) return; 85 | isAnimating = true; 86 | 87 | // Animate content image 88 | gsap.to(content.querySelector('.content__img'), { 89 | duration: 0.8, 90 | ease: 'power3.inOut', 91 | yPercent: -15, 92 | opacity: 0 93 | }); 94 | 95 | overlay.show({ 96 | // Specify the cell's transform origin 97 | transformOrigin: '50% 100%', 98 | // Duration for each cell animation 99 | duration: 0.4, 100 | // Ease for each cell animation 101 | ease: 'power3.inOut', 102 | // Stagger function 103 | stagger: (index, _, array) => 0.03 * (overlay.cells.flat()[array.length-index-1].row + gsap.utils.random(0,5)) 104 | }) 105 | .then(() => { 106 | // hide content 107 | intro.classList.remove('intro--closed'); 108 | content.classList.remove('content--open'); 109 | // Now hide the overlay 110 | overlay.hide({ 111 | // Specify the cell's transform origin 112 | transformOrigin: '50% 0%', 113 | // Duration for each cell animation 114 | duration: 0.4, 115 | // Ease for each cell animation 116 | ease: 'power2', 117 | // Stagger function 118 | stagger: (index, _, array) => 0.03 * (overlay.cells.flat()[array.length-index-1].row + gsap.utils.random(0,5)) 119 | }).then(() => isAnimating = false); 120 | 121 | // Animate intro section 122 | gsap.to(intro, { 123 | duration: 0.8, 124 | ease: 'power3', 125 | yPercent: 0, 126 | opacity: 1 127 | }); 128 | }) 129 | 130 | }); 131 | }); 132 | 133 | // Preload images and fonts and remove loader 134 | Promise.all([ 135 | preloadImages('.intro__image, .content__img-inner'), 136 | preloadFonts('ctp6pec') 137 | ]).then(() => document.body.classList.remove('loading')); -------------------------------------------------------------------------------- /js/demo1/overlay.js: -------------------------------------------------------------------------------- 1 | 2 | // Cell class definition 3 | class Cell { 4 | DOM = { 5 | el: null 6 | }; 7 | row; 8 | column; 9 | 10 | constructor(row, column) { 11 | this.DOM.el = document.createElement('div'); 12 | gsap.set(this.DOM.el, {willChange: 'opacity, transform'}); 13 | this.row = row; 14 | this.column = column; 15 | } 16 | } 17 | 18 | // Overlay class definition 19 | export class Overlay { 20 | DOM = { 21 | el: null 22 | }; 23 | // cells array 24 | cells = []; 25 | // options 26 | options = { 27 | // Number of cell rows 28 | rows: 10, 29 | // Number of cell columns 30 | columns: 10, 31 | }; 32 | 33 | // Constructor accepts a DOM element representing the overlay 34 | constructor(DOM_el, customOptions) { 35 | this.DOM.el = DOM_el; 36 | 37 | // Merge default options with provided options 38 | this.options = Object.assign({}, this.options, customOptions); 39 | 40 | // Set the value of the CSS variable 41 | this.DOM.el.style.setProperty('--columns', this.options.columns); 42 | 43 | // Create an array of all cells 44 | this.cells = new Array(this.options.rows); 45 | for (let i = 0; i < this.options.rows; ++i) { 46 | this.cells[i] = new Array(this.options.columns); 47 | } 48 | 49 | // Fill the array with values 50 | for (let i = 0; i < this.options.rows; ++i) { 51 | for (let j = 0; j < this.options.columns; ++j) { 52 | const cell = new Cell(i,j); 53 | this.cells[i][j] = cell; 54 | this.DOM.el.appendChild(cell.DOM.el); 55 | } 56 | } 57 | } 58 | 59 | // Show the overlay and animate the cells in 60 | show(customConfig = {}) { 61 | return new Promise((resolve) => { 62 | // Default animation configuration 63 | const defaultConfig = { 64 | // Specify the cell's transform origin 65 | transformOrigin: '50% 50%', 66 | // Duration for each cell animation 67 | duration: 0.5, 68 | // Ease for each cell animation 69 | ease: 'none', 70 | // Stagger object 71 | stagger: { 72 | grid: [this.options.rows, this.options.columns], 73 | from: 0, 74 | each: 0.05, 75 | ease: 'none' 76 | } 77 | }; 78 | const config = Object.assign({}, defaultConfig, customConfig); 79 | 80 | gsap.set(this.DOM.el, {opacity: 1}); 81 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 82 | scale: 0, 83 | opacity: 0, 84 | transformOrigin: config.transformOrigin 85 | }, { 86 | duration: config.duration, 87 | ease: config.ease, 88 | scale: 1.01, 89 | opacity: 1, 90 | stagger: config.stagger, 91 | onComplete: resolve 92 | }); 93 | }); 94 | } 95 | // Hide the overlay and animate the cells out 96 | hide(customConfig = {}) { 97 | return new Promise((resolve) => { 98 | // Default animation configuration 99 | const defaultConfig = { 100 | transformOrigin: '50% 50%', 101 | // Duration for each cell animation 102 | duration: 0.5, 103 | // Ease for each cell animation 104 | ease: 'none', 105 | // Stagger object 106 | stagger: { 107 | grid: [this.options.rows, this.options.columns], 108 | from: 0, 109 | each: 0.05, 110 | ease: 'none' 111 | } 112 | }; 113 | const config = Object.assign({}, defaultConfig, customConfig); 114 | 115 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 116 | transformOrigin: config.transformOrigin 117 | }, { 118 | duration: config.duration, 119 | ease: config.ease, 120 | scale: 0, 121 | opacity: 0, 122 | stagger: config.stagger, 123 | onComplete: resolve 124 | }); 125 | }); 126 | } 127 | } -------------------------------------------------------------------------------- /js/demo2/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages, preloadFonts } from '../utils.js'; 2 | import { Overlay } from './overlay.js'; 3 | 4 | // Select the overlay element from the DOM 5 | const overlayEl = document.querySelector('.overlay'); 6 | 7 | // Intro 8 | const intro = document.querySelector('.intro'); 9 | 10 | // Intro images 11 | const images = [...intro.querySelectorAll('.intro__image')]; 12 | 13 | // Content elements 14 | const contentElements = [...document.querySelectorAll('.content-wrap > .content')]; 15 | 16 | // Instantiate an Overlay object using the selected overlay element 17 | const overlay = new Overlay(overlayEl, { 18 | rows: 9, 19 | columns: 17 20 | }); 21 | 22 | let isAnimating = false; 23 | 24 | // Attach click event listeners to each intro image 25 | images.forEach((image, position) => { 26 | // Show the overlay when an intro image is clicked 27 | image.addEventListener('click', () => { 28 | if ( isAnimating ) return; 29 | isAnimating = true; 30 | 31 | // Animate intro section 32 | gsap.to(intro, { 33 | duration: 1, 34 | ease: 'power3.inOut', 35 | scaleX: 1.8, 36 | opacity: 0 37 | }); 38 | 39 | overlay.show({ 40 | // Duration for each cell animation 41 | duration: 0.25, 42 | // Ease for each cell animation 43 | ease: 'power1.in', 44 | // Stagger object 45 | stagger: { 46 | grid: [overlay.options.rows, overlay.options.columns], 47 | from: 'center', 48 | each: 0.025 49 | } 50 | }) 51 | .then(() => { 52 | // show content 53 | intro.classList.add('intro--closed'); 54 | contentElements[position].classList.add('content--open'); 55 | 56 | // Now hide the overlay 57 | overlay.hide({ 58 | // Duration for each cell animation 59 | duration: 0.25, 60 | // Ease for each cell animation 61 | ease: 'power1', 62 | // Stagger object 63 | stagger: { 64 | grid: [overlay.options.rows, overlay.options.columns], 65 | from: 'center', 66 | each: 0.025 67 | } 68 | }).then(() => isAnimating = false); 69 | 70 | // Animate content image 71 | gsap.fromTo(contentElements[position].querySelector('.content__img'), { 72 | scaleX: 0.5, 73 | opacity: 0 74 | }, { 75 | duration: 0.8, 76 | ease: 'power3', 77 | scaleX: 1, 78 | opacity: 1 79 | }); 80 | }) 81 | 82 | }); 83 | }); 84 | 85 | // Attach click event listeners to each content back button 86 | contentElements.forEach((content) => { 87 | content.querySelector('.content__back').addEventListener('click', () => { 88 | if ( isAnimating ) return; 89 | isAnimating = true; 90 | 91 | // Animate content image 92 | gsap.to(content.querySelector('.content__img'), { 93 | duration: 0.7, 94 | ease: 'power2.in', 95 | scaleX: 0.75, 96 | opacity: 0 97 | }); 98 | 99 | overlay.show({ 100 | // Duration for each cell animation 101 | duration: 0.25, 102 | // Ease for each cell animation 103 | ease: 'power1.in', 104 | // Stagger object 105 | stagger: { 106 | grid: [overlay.options.rows, overlay.options.columns], 107 | from: 'edges', 108 | each: 0.025 109 | } 110 | }) 111 | .then(() => { 112 | // hide content here 113 | intro.classList.remove('intro--closed'); 114 | content.classList.remove('content--open'); 115 | 116 | // Now hide the overlay 117 | overlay.hide({ 118 | // Duration for each cell animation 119 | duration: 0.25, 120 | // Ease for each cell animation 121 | ease: 'power1', 122 | // Stagger object 123 | stagger: { 124 | grid: [overlay.options.rows, overlay.options.columns], 125 | from: 'edges', 126 | each: 0.025 127 | } 128 | }).then(() => isAnimating = false); 129 | 130 | // Animate intro section 131 | gsap.to(intro, { 132 | duration: 0.8, 133 | ease: 'expo', 134 | scaleX: 1, 135 | opacity: 1 136 | }); 137 | }) 138 | 139 | }); 140 | }); 141 | 142 | // Preload images and fonts and remove loader 143 | Promise.all([ 144 | preloadImages('.intro__image, .content__img-inner'), 145 | preloadFonts('ctp6pec') 146 | ]).then(() => document.body.classList.remove('loading')); -------------------------------------------------------------------------------- /js/demo2/overlay.js: -------------------------------------------------------------------------------- 1 | 2 | // Cell class definition 3 | class Cell { 4 | DOM = { 5 | el: null 6 | }; 7 | row; 8 | column; 9 | 10 | constructor(row, column) { 11 | this.DOM.el = document.createElement('div'); 12 | gsap.set(this.DOM.el, {willChange: 'opacity, transform'}); 13 | this.row = row; 14 | this.column = column; 15 | } 16 | } 17 | 18 | // Overlay class definition 19 | export class Overlay { 20 | DOM = { 21 | el: null 22 | }; 23 | // cells array 24 | cells = []; 25 | // options 26 | options = { 27 | // Number of cell rows 28 | rows: 10, 29 | // Number of cell columns 30 | columns: 10, 31 | }; 32 | 33 | // Constructor accepts a DOM element representing the overlay 34 | constructor(DOM_el, customOptions) { 35 | this.DOM.el = DOM_el; 36 | 37 | // Merge default options with provided options 38 | this.options = Object.assign({}, this.options, customOptions); 39 | 40 | // Set the value of the CSS variable 41 | this.DOM.el.style.setProperty('--columns', this.options.columns); 42 | 43 | // Create an array of all cells 44 | this.cells = new Array(this.options.rows); 45 | for (let i = 0; i < this.options.rows; ++i) { 46 | this.cells[i] = new Array(this.options.columns); 47 | } 48 | 49 | // Fill the array with values 50 | for (let i = 0; i < this.options.rows; ++i) { 51 | for (let j = 0; j < this.options.columns; ++j) { 52 | const cell = new Cell(i,j); 53 | this.cells[i][j] = cell; 54 | this.DOM.el.appendChild(cell.DOM.el); 55 | } 56 | } 57 | } 58 | 59 | // Show the overlay and animate the cells in 60 | show(customConfig = {}) { 61 | return new Promise((resolve) => { 62 | // Default animation configuration 63 | const defaultConfig = { 64 | // Specify the cell's transform origin 65 | transformOrigin: '50% 50%', 66 | // Duration for each cell animation 67 | duration: 0.5, 68 | // Ease for each cell animation 69 | ease: 'none', 70 | // Stagger object 71 | stagger: { 72 | grid: [this.options.rows, this.options.columns], 73 | from: 0, 74 | each: 0.05, 75 | ease: 'none' 76 | } 77 | }; 78 | const config = Object.assign({}, defaultConfig, customConfig); 79 | 80 | gsap.set(this.DOM.el, {opacity: 1}); 81 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 82 | scale: 0, 83 | opacity: 0, 84 | transformOrigin: config.transformOrigin 85 | }, { 86 | duration: config.duration, 87 | ease: config.ease, 88 | scale: 1.03, 89 | opacity: 1, 90 | stagger: config.stagger, 91 | onComplete: resolve 92 | }); 93 | }); 94 | } 95 | // Hide the overlay and animate the cells out 96 | hide(customConfig = {}) { 97 | return new Promise((resolve) => { 98 | // Default animation configuration 99 | const defaultConfig = { 100 | transformOrigin: '50% 50%', 101 | // Duration for each cell animation 102 | duration: 0.5, 103 | // Ease for each cell animation 104 | ease: 'none', 105 | // Stagger object 106 | stagger: { 107 | grid: [this.options.rows, this.options.columns], 108 | from: 0, 109 | each: 0.05, 110 | ease: 'none' 111 | } 112 | }; 113 | const config = Object.assign({}, defaultConfig, customConfig); 114 | 115 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 116 | transformOrigin: config.transformOrigin 117 | }, { 118 | duration: config.duration, 119 | ease: config.ease, 120 | scale: 0, 121 | opacity: 0, 122 | stagger: config.stagger, 123 | onComplete: resolve 124 | }); 125 | }); 126 | } 127 | } -------------------------------------------------------------------------------- /js/demo3/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages, preloadFonts } from '../utils.js'; 2 | import { Overlay } from './overlay.js'; 3 | 4 | // Select the overlay element from the DOM 5 | const overlayEl = document.querySelector('.overlay'); 6 | 7 | // Intro 8 | const intro = document.querySelector('.intro'); 9 | 10 | // Intro images 11 | const images = [...intro.querySelectorAll('.intro__image')]; 12 | 13 | // Content elements 14 | const contentElements = [...document.querySelectorAll('.content-wrap > .content')]; 15 | 16 | // Instantiate an Overlay object using the selected overlay element 17 | const overlay = new Overlay(overlayEl, { 18 | rows: 7, 19 | columns: 13 20 | }); 21 | 22 | let isAnimating = false; 23 | 24 | // Attach click event listeners to each intro image 25 | images.forEach((image, position) => { 26 | // Show the overlay when an intro image is clicked 27 | image.addEventListener('click', () => { 28 | if ( isAnimating ) return; 29 | isAnimating = true; 30 | 31 | // Animate intro section 32 | gsap.to(intro, { 33 | duration: 0.7, 34 | ease: 'power2.in', 35 | scale: 0.75 36 | }); 37 | 38 | overlay.show({ 39 | // Duration for each cell animation 40 | duration: 0.3, 41 | // Ease for each cell animation 42 | ease: 'power1.inOut', 43 | // Stagger object 44 | stagger: { 45 | grid: [overlay.options.rows, overlay.options.columns], 46 | from: 'end', 47 | each: 0.035 48 | } 49 | }) 50 | .then(() => { 51 | // show content 52 | intro.classList.add('intro--closed'); 53 | contentElements[position].classList.add('content--open'); 54 | 55 | // Now hide the overlay 56 | overlay.hide({ 57 | // Duration for each cell animation 58 | duration: 0.3, 59 | // Ease for each cell animation 60 | ease: 'power3', 61 | // Stagger object 62 | stagger: { 63 | grid: [overlay.options.rows, overlay.options.columns], 64 | from: 'end', 65 | each: 0.035 66 | } 67 | }).then(() => isAnimating = false); 68 | 69 | // Animate content image 70 | gsap.fromTo(contentElements[position].querySelector('.content__img'), { 71 | scale: 1.2 72 | }, { 73 | duration: 0.9, 74 | ease: 'expo', 75 | scale: 1 76 | }); 77 | }) 78 | 79 | }); 80 | }); 81 | 82 | // Attach click event listeners to each content back button 83 | contentElements.forEach((content) => { 84 | content.querySelector('.content__back').addEventListener('click', () => { 85 | if ( isAnimating ) return; 86 | isAnimating = true; 87 | 88 | // Animate content image 89 | gsap.to(content.querySelector('.content__img'), { 90 | duration: 0.7, 91 | ease: 'power2.in', 92 | scale: 1.2 93 | }); 94 | 95 | overlay.show({ 96 | // Duration for each cell animation 97 | duration: 0.3, 98 | // Ease for each cell animation 99 | ease: 'power1.inOut', 100 | // Stagger object 101 | stagger: { 102 | grid: [overlay.options.rows, overlay.options.columns], 103 | from: 'start', 104 | each: 0.035 105 | } 106 | }) 107 | .then(() => { 108 | // hide content here 109 | intro.classList.remove('intro--closed'); 110 | content.classList.remove('content--open'); 111 | 112 | // Now hide the overlay 113 | overlay.hide({ 114 | // Duration for each cell animation 115 | duration: 0.3, 116 | // Ease for each cell animation 117 | ease: 'power3', 118 | // Stagger object 119 | stagger: { 120 | grid: [overlay.options.rows, overlay.options.columns], 121 | from: 'start', 122 | each: 0.035 123 | } 124 | }).then(() => isAnimating = false); 125 | 126 | // Animate intro section 127 | gsap.to(intro, { 128 | duration: 0.9, 129 | ease: 'expo', 130 | scale: 1 131 | }); 132 | }) 133 | 134 | }); 135 | }); 136 | 137 | // Preload images and fonts and remove loader 138 | Promise.all([ 139 | preloadImages('.intro__image, .content__img-inner'), 140 | preloadFonts('ctp6pec') 141 | ]).then(() => document.body.classList.remove('loading')); -------------------------------------------------------------------------------- /js/demo3/overlay.js: -------------------------------------------------------------------------------- 1 | 2 | // Cell class definition 3 | class Cell { 4 | DOM = { 5 | el: null 6 | }; 7 | row; 8 | column; 9 | 10 | constructor(row, column) { 11 | this.DOM.el = document.createElement('div'); 12 | gsap.set(this.DOM.el, {willChange: 'opacity, transform'}); 13 | this.row = row; 14 | this.column = column; 15 | } 16 | } 17 | 18 | // Overlay class definition 19 | export class Overlay { 20 | DOM = { 21 | el: null 22 | }; 23 | // cells array 24 | cells = []; 25 | // options 26 | options = { 27 | // Number of cell rows 28 | rows: 10, 29 | // Number of cell columns 30 | columns: 10, 31 | }; 32 | 33 | // Constructor accepts a DOM element representing the overlay 34 | constructor(DOM_el, customOptions) { 35 | this.DOM.el = DOM_el; 36 | 37 | // Merge default options with provided options 38 | this.options = Object.assign({}, this.options, customOptions); 39 | 40 | // Set the value of the CSS variable 41 | this.DOM.el.style.setProperty('--columns', this.options.columns); 42 | 43 | // Create an array of all cells 44 | this.cells = new Array(this.options.rows); 45 | for (let i = 0; i < this.options.rows; ++i) { 46 | this.cells[i] = new Array(this.options.columns); 47 | } 48 | 49 | // Fill the array with values 50 | for (let i = 0; i < this.options.rows; ++i) { 51 | for (let j = 0; j < this.options.columns; ++j) { 52 | const cell = new Cell(i,j); 53 | this.cells[i][j] = cell; 54 | this.DOM.el.appendChild(cell.DOM.el); 55 | } 56 | } 57 | } 58 | 59 | // Show the overlay and animate the cells in 60 | show(customConfig = {}) { 61 | return new Promise((resolve) => { 62 | // Default animation configuration 63 | const defaultConfig = { 64 | // Specify the cell's transform origin 65 | transformOrigin: '50% 50%', 66 | // Duration for each cell animation 67 | duration: 0.5, 68 | // Ease for each cell animation 69 | ease: 'none', 70 | // Stagger object 71 | stagger: { 72 | grid: [this.options.rows, this.options.columns], 73 | from: 0, 74 | each: 0.05, 75 | ease: 'none' 76 | } 77 | }; 78 | const config = Object.assign({}, defaultConfig, customConfig); 79 | 80 | gsap.set(this.DOM.el, {opacity: 1}); 81 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 82 | scale: 0, 83 | opacity: 0, 84 | transformOrigin: config.transformOrigin 85 | }, { 86 | duration: config.duration, 87 | ease: config.ease, 88 | scale: 1.01, 89 | opacity: 1, 90 | stagger: config.stagger, 91 | onComplete: resolve 92 | }); 93 | }); 94 | } 95 | // Hide the overlay and animate the cells out 96 | hide(customConfig = {}) { 97 | return new Promise((resolve) => { 98 | // Default animation configuration 99 | const defaultConfig = { 100 | transformOrigin: '50% 50%', 101 | // Duration for each cell animation 102 | duration: 0.5, 103 | // Ease for each cell animation 104 | ease: 'none', 105 | // Stagger object 106 | stagger: { 107 | grid: [this.options.rows, this.options.columns], 108 | from: 0, 109 | each: 0.05, 110 | ease: 'none' 111 | } 112 | }; 113 | const config = Object.assign({}, defaultConfig, customConfig); 114 | 115 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 116 | transformOrigin: config.transformOrigin 117 | }, { 118 | duration: config.duration, 119 | ease: config.ease, 120 | scale: 0, 121 | opacity: 0, 122 | stagger: config.stagger, 123 | onComplete: resolve 124 | }); 125 | }); 126 | } 127 | } -------------------------------------------------------------------------------- /js/demo4/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages, preloadFonts } from '../utils.js'; 2 | import { Overlay } from './overlay.js'; 3 | 4 | // Select the overlay element from the DOM 5 | const overlayEl = document.querySelector('.overlay'); 6 | 7 | // Intro 8 | const intro = document.querySelector('.intro'); 9 | 10 | // Intro images 11 | const images = [...intro.querySelectorAll('.intro__image')]; 12 | 13 | // Content elements 14 | const contentElements = [...document.querySelectorAll('.content-wrap > .content')]; 15 | 16 | // Instantiate an Overlay object using the selected overlay element 17 | const overlay = new Overlay(overlayEl, { 18 | rows: 9, 19 | columns: 17 20 | }); 21 | 22 | let isAnimating = false; 23 | 24 | // Attach click event listeners to each intro image 25 | images.forEach((image, position) => { 26 | // Show the overlay when an intro image is clicked 27 | image.addEventListener('click', () => { 28 | if ( isAnimating ) return; 29 | isAnimating = true; 30 | 31 | // Animate intro section 32 | gsap.to(intro, { 33 | duration: 0.7, 34 | ease: 'power2.in', 35 | scale: 0.75, 36 | opacity: 0 37 | }); 38 | 39 | overlay.show({ 40 | // Duration for each cell animation 41 | duration: 0.25, 42 | // Ease for each cell animation 43 | ease: 'power1.in', 44 | // Stagger object 45 | stagger: { 46 | grid: [overlay.options.rows, overlay.options.columns], 47 | from: 'edges', 48 | each: 0.025 49 | } 50 | }) 51 | .then(() => { 52 | // show content 53 | intro.classList.add('intro--closed'); 54 | contentElements[position].classList.add('content--open'); 55 | 56 | // Now hide the overlay 57 | overlay.hide({ 58 | // Duration for each cell animation 59 | duration: 0.25, 60 | // Ease for each cell animation 61 | ease: 'power1', 62 | // Stagger object 63 | stagger: { 64 | grid: [overlay.options.rows, overlay.options.columns], 65 | from: 'center', 66 | each: 0.025 67 | } 68 | }).then(() => isAnimating = false); 69 | 70 | // Animate content image 71 | gsap.fromTo(contentElements[position].querySelector('.content__img'), { 72 | scale: 0.5, 73 | opacity: 0 74 | }, { 75 | duration: 0.8, 76 | ease: 'power4', 77 | scale: 1, 78 | opacity: 1 79 | }); 80 | }) 81 | 82 | }); 83 | }); 84 | 85 | // Attach click event listeners to each content back button 86 | contentElements.forEach((content) => { 87 | content.querySelector('.content__back').addEventListener('click', () => { 88 | if ( isAnimating ) return; 89 | isAnimating = true; 90 | 91 | // Animate content image 92 | gsap.to(content.querySelector('.content__img'), { 93 | duration: 0.7, 94 | ease: 'power2.in', 95 | scale: 0.75, 96 | opacity: 0 97 | }); 98 | 99 | overlay.show({ 100 | // Duration for each cell animation 101 | duration: 0.25, 102 | // Ease for each cell animation 103 | ease: 'power1.in', 104 | // Stagger object 105 | stagger: { 106 | grid: [overlay.options.rows, overlay.options.columns], 107 | from: 'edges', 108 | each: 0.025 109 | } 110 | }) 111 | .then(() => { 112 | // hide content here 113 | intro.classList.remove('intro--closed'); 114 | content.classList.remove('content--open'); 115 | 116 | // Now hide the overlay 117 | overlay.hide({ 118 | // Duration for each cell animation 119 | duration: 0.25, 120 | // Ease for each cell animation 121 | ease: 'power1', 122 | // Stagger object 123 | stagger: { 124 | grid: [overlay.options.rows, overlay.options.columns], 125 | from: 'center', 126 | each: 0.025 127 | } 128 | }).then(() => isAnimating = false); 129 | 130 | // Animate intro section 131 | gsap.to(intro, { 132 | duration: 0.8, 133 | ease: 'power4', 134 | scale: 1, 135 | opacity: 1 136 | }); 137 | }) 138 | 139 | }); 140 | }); 141 | 142 | // Preload images and fonts and remove loader 143 | Promise.all([ 144 | preloadImages('.intro__image, .content__img-inner'), 145 | preloadFonts('ctp6pec') 146 | ]).then(() => document.body.classList.remove('loading')); -------------------------------------------------------------------------------- /js/demo4/overlay.js: -------------------------------------------------------------------------------- 1 | 2 | // Cell class definition 3 | class Cell { 4 | DOM = { 5 | el: null 6 | }; 7 | row; 8 | column; 9 | 10 | constructor(row, column) { 11 | this.DOM.el = document.createElement('div'); 12 | gsap.set(this.DOM.el, {willChange: 'opacity, transform'}); 13 | this.row = row; 14 | this.column = column; 15 | } 16 | } 17 | 18 | // Overlay class definition 19 | export class Overlay { 20 | DOM = { 21 | el: null 22 | }; 23 | // cells array 24 | cells = []; 25 | // options 26 | options = { 27 | // Number of cell rows 28 | rows: 10, 29 | // Number of cell columns 30 | columns: 10, 31 | }; 32 | 33 | // Constructor accepts a DOM element representing the overlay 34 | constructor(DOM_el, customOptions) { 35 | this.DOM.el = DOM_el; 36 | 37 | // Merge default options with provided options 38 | this.options = Object.assign({}, this.options, customOptions); 39 | 40 | // Set the value of the CSS variable 41 | this.DOM.el.style.setProperty('--columns', this.options.columns); 42 | 43 | // Create an array of all cells 44 | this.cells = new Array(this.options.rows); 45 | for (let i = 0; i < this.options.rows; ++i) { 46 | this.cells[i] = new Array(this.options.columns); 47 | } 48 | 49 | // Fill the array with values 50 | for (let i = 0; i < this.options.rows; ++i) { 51 | for (let j = 0; j < this.options.columns; ++j) { 52 | const cell = new Cell(i,j); 53 | this.cells[i][j] = cell; 54 | this.DOM.el.appendChild(cell.DOM.el); 55 | } 56 | } 57 | } 58 | 59 | // Show the overlay and animate the cells in 60 | show(customConfig = {}) { 61 | return new Promise((resolve) => { 62 | // Default animation configuration 63 | const defaultConfig = { 64 | // Specify the cell's transform origin 65 | transformOrigin: '50% 50%', 66 | // Duration for each cell animation 67 | duration: 0.5, 68 | // Ease for each cell animation 69 | ease: 'none', 70 | // Stagger object 71 | stagger: { 72 | grid: [this.options.rows, this.options.columns], 73 | from: 0, 74 | each: 0.05, 75 | ease: 'none' 76 | } 77 | }; 78 | const config = Object.assign({}, defaultConfig, customConfig); 79 | 80 | gsap.set(this.DOM.el, {opacity: 1}); 81 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 82 | scale: 0, 83 | opacity: 0, 84 | transformOrigin: config.transformOrigin 85 | }, { 86 | duration: config.duration, 87 | ease: config.ease, 88 | scale: 1.03, 89 | opacity: 1, 90 | stagger: config.stagger, 91 | onComplete: resolve 92 | }); 93 | }); 94 | } 95 | // Hide the overlay and animate the cells out 96 | hide(customConfig = {}) { 97 | return new Promise((resolve) => { 98 | // Default animation configuration 99 | const defaultConfig = { 100 | transformOrigin: '50% 50%', 101 | // Duration for each cell animation 102 | duration: 0.5, 103 | // Ease for each cell animation 104 | ease: 'none', 105 | // Stagger object 106 | stagger: { 107 | grid: [this.options.rows, this.options.columns], 108 | from: 0, 109 | each: 0.05, 110 | ease: 'none' 111 | } 112 | }; 113 | const config = Object.assign({}, defaultConfig, customConfig); 114 | 115 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 116 | transformOrigin: config.transformOrigin 117 | }, { 118 | duration: config.duration, 119 | ease: config.ease, 120 | scale: 0, 121 | opacity: 0, 122 | stagger: config.stagger, 123 | onComplete: resolve 124 | }); 125 | }); 126 | } 127 | } -------------------------------------------------------------------------------- /js/demo5/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages, preloadFonts } from '../utils.js'; 2 | import { Overlay } from './overlay.js'; 3 | 4 | // Select the overlay element from the DOM 5 | const overlayEl = document.querySelector('.overlay'); 6 | 7 | // Intro 8 | const intro = document.querySelector('.intro'); 9 | 10 | // Intro images 11 | const images = [...intro.querySelectorAll('.intro__image')]; 12 | 13 | // Content elements 14 | const contentElements = [...document.querySelectorAll('.content-wrap > .content')]; 15 | 16 | // Instantiate an Overlay object using the selected overlay element 17 | const overlay = new Overlay(overlayEl, { 18 | rows: 20, 19 | columns: 4 20 | }); 21 | 22 | let isAnimating = false; 23 | 24 | // Attach click event listeners to each intro image 25 | images.forEach((image, position) => { 26 | // Show the overlay when an intro image is clicked 27 | image.addEventListener('click', () => { 28 | if ( isAnimating ) return; 29 | isAnimating = true; 30 | 31 | // Animate intro section 32 | gsap.to(intro, { 33 | duration: 0.7, 34 | ease: 'power2.in', 35 | startAt: {filter: 'brightness(100%) saturate(100%)'}, 36 | filter: 'brightness(800%) saturate(600%)', 37 | }); 38 | 39 | overlay.show({ 40 | // Specify the cell's transform origin 41 | transformOrigin: '50% 100%', 42 | // Duration for each cell animation 43 | duration: 0.3, 44 | // Ease for each cell animation 45 | ease: 'power1.in', 46 | // Stagger object 47 | stagger: { 48 | grid: [overlay.options.rows, overlay.options.columns], 49 | from: 'start', 50 | each: 0.02 51 | } 52 | }) 53 | .then(() => { 54 | // show content 55 | intro.classList.add('intro--closed'); 56 | contentElements[position].classList.add('content--open'); 57 | 58 | // Now hide the overlay 59 | overlay.hide({ 60 | // Specify the cell's transform origin 61 | transformOrigin: '50% 0%', 62 | // Duration for each cell animation 63 | duration: 0.3, 64 | // Ease for each cell animation 65 | ease: 'power3', 66 | // Stagger object 67 | stagger: { 68 | grid: [overlay.options.rows, overlay.options.columns], 69 | from: 'start', 70 | each: 0.02 71 | } 72 | }).then(() => isAnimating = false); 73 | 74 | // Animate content image 75 | gsap.fromTo(contentElements[position].querySelector('.content__img'), { 76 | filter: 'brightness(800%) saturate(600%)' 77 | }, { 78 | duration: 0.8, 79 | ease: 'power4', 80 | filter: 'brightness(100%) saturate(100%)' 81 | }); 82 | }) 83 | 84 | }); 85 | }); 86 | 87 | // Attach click event listeners to each content back button 88 | contentElements.forEach((content) => { 89 | content.querySelector('.content__back').addEventListener('click', () => { 90 | if ( isAnimating ) return; 91 | isAnimating = true; 92 | 93 | // Animate content image 94 | gsap.to(content.querySelector('.content__img'), { 95 | duration: 0.7, 96 | ease: 'power2.in', 97 | filter: 'brightness(800%) saturate(600%)', 98 | }); 99 | 100 | overlay.show({ 101 | // Specify the cell's transform origin 102 | transformOrigin: '50% 0%', 103 | // Duration for each cell animation 104 | duration: 0.3, 105 | // Ease for each cell animation 106 | ease: 'power1.in', 107 | // Stagger object 108 | stagger: { 109 | grid: [overlay.options.rows, overlay.options.columns], 110 | from: 'end', 111 | each: 0.02 112 | } 113 | }) 114 | .then(() => { 115 | // hide content here 116 | intro.classList.remove('intro--closed'); 117 | content.classList.remove('content--open'); 118 | 119 | // Now hide the overlay 120 | overlay.hide({ 121 | // Specify the cell's transform origin 122 | transformOrigin: '50% 100%', 123 | // Duration for each cell animation 124 | duration: 0.3, 125 | // Ease for each cell animation 126 | ease: 'power3', 127 | // Stagger object 128 | stagger: { 129 | grid: [overlay.options.rows, overlay.options.columns], 130 | from: 'end', 131 | each: 0.02 132 | } 133 | }).then(() => isAnimating = false); 134 | 135 | // Animate intro section 136 | gsap.to(intro, { 137 | duration: 0.8, 138 | ease: 'power4', 139 | filter: 'brightness(100%) saturate(100%)' 140 | }); 141 | }) 142 | 143 | }); 144 | }); 145 | 146 | // Preload images and fonts and remove loader 147 | Promise.all([ 148 | preloadImages('.intro__image, .content__img-inner'), 149 | preloadFonts('ctp6pec') 150 | ]).then(() => document.body.classList.remove('loading')); -------------------------------------------------------------------------------- /js/demo5/overlay.js: -------------------------------------------------------------------------------- 1 | 2 | // Cell class definition 3 | class Cell { 4 | DOM = { 5 | el: null 6 | }; 7 | row; 8 | column; 9 | 10 | constructor(row, column) { 11 | this.DOM.el = document.createElement('div'); 12 | gsap.set(this.DOM.el, {willChange: 'opacity, transform'}); 13 | this.row = row; 14 | this.column = column; 15 | } 16 | } 17 | 18 | // Overlay class definition 19 | export class Overlay { 20 | DOM = { 21 | el: null 22 | }; 23 | // cells array 24 | cells = []; 25 | // options 26 | options = { 27 | // Number of cell rows 28 | rows: 10, 29 | // Number of cell columns 30 | columns: 10, 31 | }; 32 | 33 | // Constructor accepts a DOM element representing the overlay 34 | constructor(DOM_el, customOptions) { 35 | this.DOM.el = DOM_el; 36 | 37 | // Merge default options with provided options 38 | this.options = Object.assign({}, this.options, customOptions); 39 | 40 | // Set the value of the CSS variable 41 | this.DOM.el.style.setProperty('--columns', this.options.columns); 42 | 43 | // Create an array of all cells 44 | this.cells = new Array(this.options.rows); 45 | for (let i = 0; i < this.options.rows; ++i) { 46 | this.cells[i] = new Array(this.options.columns); 47 | } 48 | 49 | // Fill the array with values 50 | for (let i = 0; i < this.options.rows; ++i) { 51 | for (let j = 0; j < this.options.columns; ++j) { 52 | const cell = new Cell(i,j); 53 | this.cells[i][j] = cell; 54 | this.DOM.el.appendChild(cell.DOM.el); 55 | } 56 | } 57 | } 58 | 59 | // Show the overlay and animate the cells in 60 | show(customConfig = {}) { 61 | return new Promise((resolve) => { 62 | // Default animation configuration 63 | const defaultConfig = { 64 | // Specify the cell's transform origin 65 | transformOrigin: '50% 50%', 66 | // Duration for each cell animation 67 | duration: 0.5, 68 | // Ease for each cell animation 69 | ease: 'none', 70 | // Stagger object 71 | stagger: { 72 | grid: [this.options.rows, this.options.columns], 73 | from: 0, 74 | each: 0.05, 75 | ease: 'none' 76 | } 77 | }; 78 | const config = Object.assign({}, defaultConfig, customConfig); 79 | 80 | gsap.set(this.DOM.el, {opacity: 1}); 81 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 82 | scaleY: 0, 83 | opacity: 0, 84 | transformOrigin: config.transformOrigin 85 | }, { 86 | duration: config.duration, 87 | ease: config.ease, 88 | scaleY: 1.03, 89 | opacity: 1, 90 | stagger: config.stagger, 91 | onComplete: resolve 92 | }); 93 | }); 94 | } 95 | // Hide the overlay and animate the cells out 96 | hide(customConfig = {}) { 97 | return new Promise((resolve) => { 98 | // Default animation configuration 99 | const defaultConfig = { 100 | transformOrigin: '50% 50%', 101 | // Duration for each cell animation 102 | duration: 0.5, 103 | // Ease for each cell animation 104 | ease: 'none', 105 | // Stagger object 106 | stagger: { 107 | grid: [this.options.rows, this.options.columns], 108 | from: 0, 109 | each: 0.05, 110 | ease: 'none' 111 | } 112 | }; 113 | const config = Object.assign({}, defaultConfig, customConfig); 114 | 115 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 116 | transformOrigin: config.transformOrigin 117 | }, { 118 | duration: config.duration, 119 | ease: config.ease, 120 | scaleY: 0, 121 | opacity: 0, 122 | stagger: config.stagger, 123 | onComplete: resolve 124 | }); 125 | }); 126 | } 127 | } -------------------------------------------------------------------------------- /js/demo6/index.js: -------------------------------------------------------------------------------- 1 | import { preloadImages, preloadFonts } from '../utils.js'; 2 | import { Overlay } from './overlay.js'; 3 | 4 | // Select the overlay element from the DOM 5 | const overlayEl = document.querySelector('.overlay'); 6 | 7 | // Intro 8 | const intro = document.querySelector('.intro'); 9 | 10 | // Intro images 11 | const images = [...intro.querySelectorAll('.intro__image')]; 12 | 13 | // Content elements 14 | const contentElements = [...document.querySelectorAll('.content-wrap > .content')]; 15 | 16 | // Instantiate an Overlay object using the selected overlay element 17 | const overlay = new Overlay(overlayEl, { 18 | rows: 6, 19 | columns: 11 20 | }); 21 | 22 | let isAnimating = false; 23 | 24 | // Attach click event listeners to each intro image 25 | images.forEach((image, position) => { 26 | // Show the overlay when an intro image is clicked 27 | image.addEventListener('click', () => { 28 | if ( isAnimating ) return; 29 | isAnimating = true; 30 | 31 | // Animate intro section 32 | gsap.to(intro, { 33 | duration: 1.1, 34 | ease: 'power3.inOut', 35 | xPercent: 5, 36 | opacity: 0 37 | }); 38 | 39 | overlay.show({ 40 | // Specify the cell's transform origin 41 | transformOrigin: '0% 50%', 42 | // Duration for each cell animation 43 | duration: 0.3, 44 | // Ease for each cell animation 45 | ease: 'power4.in', 46 | // Stagger object 47 | stagger: { 48 | grid: [overlay.options.rows, overlay.options.columns], 49 | from: 'start', 50 | each: 0.04 51 | } 52 | }) 53 | .then(() => { 54 | // show content 55 | intro.classList.add('intro--closed'); 56 | contentElements[position].classList.add('content--open'); 57 | 58 | // Now hide the overlay 59 | overlay.hide({ 60 | // Specify the cell's transform origin 61 | transformOrigin: '100% 50%', 62 | // Duration for each cell animation 63 | duration: 0.5, 64 | // Ease for each cell animation 65 | ease: 'power4', 66 | // Stagger function 67 | stagger: { 68 | grid: [overlay.options.rows, overlay.options.columns], 69 | from: 'start', 70 | each: 0.04 71 | } 72 | }).then(() => isAnimating = false); 73 | 74 | // Animate content image 75 | gsap.fromTo(contentElements[position].querySelector('.content__img'), { 76 | xPercent: -10, 77 | opacity: 0 78 | }, { 79 | duration: 0.9, 80 | ease: 'power4', 81 | xPercent: 0, 82 | opacity: 1 83 | }); 84 | }) 85 | 86 | }); 87 | }); 88 | 89 | // Attach click event listeners to each content back button 90 | contentElements.forEach((content, position) => { 91 | content.querySelector('.content__back').addEventListener('click', () => { 92 | if ( isAnimating ) return; 93 | isAnimating = true; 94 | 95 | // Animate content image 96 | gsap.to(content.querySelector('.content__img'), { 97 | duration: 1.1, 98 | ease: 'power3.inOut', 99 | xPercent: -5, 100 | opacity: 0 101 | }); 102 | 103 | overlay.show({ 104 | // Specify the cell's transform origin 105 | transformOrigin: '100% 50%', 106 | // Duration for each cell animation 107 | duration: 0.3, 108 | // Ease for each cell animation 109 | ease: 'power4.in', 110 | // Stagger function 111 | stagger: { 112 | grid: [overlay.options.rows, overlay.options.columns], 113 | from: 'end', 114 | each: 0.04 115 | } 116 | }) 117 | .then(() => { 118 | // hide content 119 | intro.classList.remove('intro--closed'); 120 | content.classList.remove('content--open'); 121 | // Now hide the overlay 122 | overlay.hide({ 123 | // Specify the cell's transform origin 124 | transformOrigin: '0% 50%', 125 | // Duration for each cell animation 126 | duration: 0.5, 127 | // Ease for each cell animation 128 | ease: 'power4', 129 | // Stagger function 130 | stagger: { 131 | grid: [overlay.options.rows, overlay.options.columns], 132 | from: 'end', 133 | each: 0.04 134 | } 135 | }).then(() => isAnimating = false); 136 | 137 | // Animate intro section 138 | gsap.fromTo(intro, { 139 | xPercent: 10, 140 | }, { 141 | duration: 0.9, 142 | ease: 'power4', 143 | xPercent: 0, 144 | opacity: 1 145 | }); 146 | }) 147 | 148 | }); 149 | }); 150 | 151 | // Preload images and fonts and remove loader 152 | Promise.all([ 153 | preloadImages('.intro__image, .content__img-inner'), 154 | preloadFonts('ctp6pec') 155 | ]).then(() => document.body.classList.remove('loading')); -------------------------------------------------------------------------------- /js/demo6/overlay.js: -------------------------------------------------------------------------------- 1 | 2 | // Cell class definition 3 | class Cell { 4 | DOM = { 5 | el: null 6 | }; 7 | row; 8 | column; 9 | 10 | constructor(row, column) { 11 | this.DOM.el = document.createElement('div'); 12 | gsap.set(this.DOM.el, {willChange: 'opacity, transform'}); 13 | this.row = row; 14 | this.column = column; 15 | } 16 | } 17 | 18 | // Overlay class definition 19 | export class Overlay { 20 | DOM = { 21 | el: null 22 | }; 23 | // cells array 24 | cells = []; 25 | // options 26 | options = { 27 | // Number of cell rows 28 | rows: 10, 29 | // Number of cell columns 30 | columns: 10, 31 | }; 32 | 33 | // Constructor accepts a DOM element representing the overlay 34 | constructor(DOM_el, customOptions) { 35 | this.DOM.el = DOM_el; 36 | 37 | // Merge default options with provided options 38 | this.options = Object.assign({}, this.options, customOptions); 39 | 40 | // Set the value of the CSS variable 41 | this.DOM.el.style.setProperty('--columns', this.options.columns); 42 | 43 | // Create an array of all cells 44 | this.cells = new Array(this.options.rows); 45 | for (let i = 0; i < this.options.rows; ++i) { 46 | this.cells[i] = new Array(this.options.columns); 47 | } 48 | 49 | // Fill the array with values 50 | for (let i = 0; i < this.options.rows; ++i) { 51 | for (let j = 0; j < this.options.columns; ++j) { 52 | const cell = new Cell(i,j); 53 | this.cells[i][j] = cell; 54 | this.DOM.el.appendChild(cell.DOM.el); 55 | } 56 | } 57 | } 58 | 59 | // Show the overlay and animate the cells in 60 | show(customConfig = {}) { 61 | return new Promise((resolve) => { 62 | // Default animation configuration 63 | const defaultConfig = { 64 | // Specify the cell's transform origin 65 | transformOrigin: '50% 50%', 66 | // Duration for each cell animation 67 | duration: 0.5, 68 | // Ease for each cell animation 69 | ease: 'none', 70 | // Stagger object 71 | stagger: { 72 | grid: [this.options.rows, this.options.columns], 73 | from: 0, 74 | each: 0.05, 75 | ease: 'none' 76 | } 77 | }; 78 | const config = Object.assign({}, defaultConfig, customConfig); 79 | 80 | gsap.set(this.DOM.el, {opacity: 1}); 81 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 82 | scaleX: 0, 83 | //opacity: 0, 84 | transformOrigin: config.transformOrigin 85 | }, { 86 | duration: config.duration, 87 | ease: config.ease, 88 | scale: 1.01, 89 | //opacity: 1, 90 | stagger: config.stagger, 91 | onComplete: resolve 92 | }); 93 | }); 94 | } 95 | // Hide the overlay and animate the cells out 96 | hide(customConfig = {}) { 97 | return new Promise((resolve) => { 98 | // Default animation configuration 99 | const defaultConfig = { 100 | transformOrigin: '50% 50%', 101 | // Duration for each cell animation 102 | duration: 0.5, 103 | // Ease for each cell animation 104 | ease: 'none', 105 | // Stagger object 106 | stagger: { 107 | grid: [this.options.rows, this.options.columns], 108 | from: 0, 109 | each: 0.05, 110 | ease: 'none' 111 | } 112 | }; 113 | const config = Object.assign({}, defaultConfig, customConfig); 114 | 115 | gsap.fromTo(this.cells.flat().map(cell => cell.DOM.el), { 116 | transformOrigin: config.transformOrigin 117 | }, { 118 | duration: config.duration, 119 | ease: config.ease, 120 | scaleX: 0, 121 | //opacity: 0, 122 | stagger: config.stagger, 123 | onComplete: resolve 124 | }); 125 | }); 126 | } 127 | } -------------------------------------------------------------------------------- /js/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Preload fonts 3 | * @param {String} id 4 | */ 5 | const preloadFonts = id => { 6 | return new Promise((resolve) => { 7 | WebFont.load({ 8 | typekit: { 9 | id: id 10 | }, 11 | active: resolve 12 | }); 13 | }); 14 | }; 15 | 16 | /** 17 | * Preload images 18 | * @param {String} selector - Selector/scope from where images need to be preloaded. Default is 'img' 19 | */ 20 | const preloadImages = (selector = 'img') => { 21 | return new Promise((resolve) => { 22 | imagesLoaded(document.querySelectorAll(selector), {background: true}, resolve); 23 | }); 24 | }; 25 | 26 | export { 27 | preloadFonts, 28 | preloadImages 29 | }; --------------------------------------------------------------------------------