├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── TODO ├── characters-and-backgrounds.zip ├── css └── main.css ├── images ├── 1.svg ├── 2.svg ├── 3.svg ├── animation-software.jpg ├── bg.png ├── boat.png ├── clicking-cursor.svg ├── download-assets.png ├── instructions-1.svg ├── instructions-2.svg ├── instructions-3.svg ├── instructions-4.svg ├── instructions-5.svg └── og.png ├── index.html ├── js └── main.js └── package.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 David Miranda 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 | # Animatize 2 | 3 | Drag a character with your mouse to create an animation 4 | 5 | ![animatize-demo](https://user-images.githubusercontent.com/364330/149359590-cf077a85-6d55-4f9e-b8ca-3f2de5e08d10.gif) 6 | 7 | ## Demo 8 | 9 | Try the demo on [Animatize.com](https://animatize.com/) 10 | 11 | ## Remix your own animation! 12 | 13 | ### Two options: 14 | 15 | #### 1. Use [the demo](https://animatize.com/) to generate code for your own site 16 | 17 | You can generate an animation using your own images and then modify the code there 18 | 19 | #### 2. Fork this project 20 | 21 | I'd love to see a powerful animation tool that uses a user's natural motion as its foundation. 22 | 23 | Feel free to build your own animation service using the code here as proof-of-concept starting point. 24 | 25 | All the code can be found in `js/main.js` 26 | 27 | ## Animating with natural movement 28 | 29 | This idea has been a dream of mine for years. As a web developer, I've never learned After Effects or any other complex animation software. 30 | 31 | I've always dreamed of creating interactive demos and animations just by using my natural mouse movements. 32 | 33 | So, in early January 2022, [I took a few days off from my main project to create Animatize](https://twitter.com/panphora/status/1478805374455140353), a proof-of-concept showing off the idea that other people could try! 34 | 35 | ## License 36 | 37 | MIT License 38 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | √ autoplay 2 | √ upload images as data urls 3 | √ make the generated code responsive 4 | √ add the design to the page 5 | √ implement generate code 6 | √ add generate code instructions with arrows 7 | √ implement start animation over 8 | √ clear generated code 9 | √ hide generated code 10 | √ erase history on user canvas element 11 | √ remove drag-started class 12 | √ reset character position 13 | 14 | implement "erase everything" button 15 | not really necessary since you can just upload new files anyways 16 | 17 | clear file inputs 18 | clear generated style element 19 | clear generated code 20 | erase history 21 | remove drag-started class 22 | reset character position 23 | add back hide-user-animations class 24 | set data-has-character & data-has-background to false 25 | -------------------------------------------------------------------------------- /characters-and-backgrounds.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panphora/animatize/224d881a9a87c287fb3a693951c95fdaa484f89a/characters-and-backgrounds.zip -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 1.5rem; 3 | line-height: 1.44; 4 | color: #212529; 5 | font-size: 21px; 6 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 7 | } 8 | 9 | .container { 10 | max-width: 532px; 11 | margin: 2.5rem auto; 12 | } 13 | 14 | .children-margin > * + * { 15 | margin-top: 2rem; 16 | } 17 | 18 | img { 19 | display: block; 20 | max-width: 100%; 21 | } 22 | 23 | h1, h2, h3, h4, h5, h6, p { 24 | margin: 0; 25 | } 26 | 27 | h1, h2, h3, h4, h5, h6 { 28 | font-size: 1rem; 29 | } 30 | 31 | .play { 32 | position: relative; 33 | margin-left: -1.5rem; 34 | margin-right: -1.5rem; 35 | padding: 2.5rem 1.5rem 2.5rem 1.5rem; 36 | border-top: 4px solid #D6336C; 37 | border-bottom: 4px solid #D6336C; 38 | background-color: #FFEAF6; 39 | } 40 | 41 | .play.blue { 42 | border-top: 4px solid #3B5BDB; 43 | border-bottom: 4px solid #3B5BDB; 44 | background-color: #DBE4FF; 45 | } 46 | 47 | .play-inner { 48 | max-width: 500px; 49 | margin: 0 auto; 50 | } 51 | 52 | 53 | .canvas { 54 | position: relative; 55 | left: 120px; 56 | max-width: 200px; 57 | } 58 | 59 | .canvas-inner { 60 | width: 100%; 61 | padding-top: 60%; 62 | background: url(../images/bg.png) top left / cover no-repeat; 63 | } 64 | 65 | .character-container { 66 | position: absolute; 67 | top: 0; 68 | left: 0; 69 | width: 100%; 70 | height: 100%; 71 | } 72 | 73 | .character { 74 | position: absolute; 75 | top: 42px; 76 | left: -60px; 77 | width: 18%; 78 | } 79 | 80 | .character-inner { 81 | width: 100%; 82 | padding-top: 100%; 83 | background: url(../images/boat.png) top left / cover no-repeat; 84 | } 85 | 86 | .canvas.full { 87 | overflow: hidden; /* to hide character when it's out of frame */ 88 | left: 0; 89 | max-width: 100%; 90 | } 91 | 92 | .canvas.full .character { 93 | top: 0; 94 | left: 0; 95 | } 96 | 97 | .canvas.full.demo .canvas-inner span { 98 | position: absolute; 99 | display: block; 100 | width: 2.7%; 101 | height: 4.5%; 102 | background-color: #FB0000; 103 | border-radius: 50%; 104 | transform: scale(.8); 105 | } 106 | 107 | .canvas.full.demo .clicking-cursor { 108 | position: absolute; 109 | left: 19.5%; 110 | top: 16%; 111 | width: 5.4%; 112 | height: 9%; 113 | } 114 | 115 | .canvas.user { 116 | left: 151px; 117 | } 118 | 119 | .canvas.user .character { 120 | left: -120px; 121 | } 122 | 123 | .intro-header { 124 | position: relative; 125 | } 126 | 127 | .intro-header .clicking-cursor { 128 | position: absolute; 129 | right: -38px; 130 | bottom: -4px; 131 | } 132 | 133 | /* 123 */ 134 | 135 | .instruction-123 { 136 | margin-bottom: 14rem; 137 | } 138 | 139 | .instruction-123 > div { 140 | display: flex; 141 | margin-bottom: 2.5rem; 142 | } 143 | 144 | .instruction-123-desc { 145 | margin-left: 1rem; 146 | } 147 | 148 | .instruction-123-desc > label { 149 | margin-bottom: .5rem; 150 | } 151 | 152 | .instruction-123-header { 153 | margin-bottom: .5rem; 154 | font-weight: bold; 155 | } 156 | 157 | .instruction-123-extra { 158 | font-size: 18px; 159 | font-weight: 600; 160 | opacity: .75; 161 | } 162 | 163 | 164 | /* instructions */ 165 | 166 | .instructions { 167 | position: absolute; 168 | pointer-events: none; 169 | max-width: none; 170 | } 171 | 172 | .instructions-1 { 173 | top: -38px; 174 | left: -125px; 175 | width: 84px; 176 | } 177 | 178 | .instructions-2 { 179 | top: -70px; 180 | left: 100px; 181 | width: 94px; 182 | } 183 | 184 | .instructions-3 { 185 | bottom: -185px; 186 | left: -105px; 187 | width: 275px; 188 | } 189 | 190 | .instructions-4 { 191 | top: 26px; 192 | left: -70px; 193 | width: 58px; 194 | } 195 | 196 | 197 | 198 | .code { 199 | display: block; 200 | width: 100%; 201 | min-height: 240px; 202 | border: 4px solid #111; 203 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 204 | } 205 | 206 | body .crostini { 207 | background-color: #1F8535; 208 | } 209 | 210 | /* labels */ 211 | 212 | .character-label, .canvas-label { 213 | position: absolute; 214 | top: 0; 215 | right: -6px; 216 | transform: translate(0, -120%); 217 | line-height: 1; 218 | font-size: 19px; 219 | font-weight: bold; 220 | } 221 | 222 | .canvas-label { 223 | right: auto; 224 | left: 0; 225 | transform: translate(0, -140%); 226 | } 227 | 228 | /* fix iOS Safari/Chrome bug with not being able to drag the character */ 229 | .draggable { 230 | touch-action: none; 231 | } 232 | 233 | .drag-started .character-label, .drag-started .canvas-label, .drag-started .instructions-4 { 234 | display: none; 235 | } 236 | 237 | /* user animation */ 238 | 239 | .hide-user-animations .canvas { 240 | display: none; 241 | } 242 | 243 | .hide-user-animations .reset-animation { 244 | display: none; 245 | } 246 | 247 | 248 | /* utils */ 249 | 250 | .inline-block { 251 | display: inline-block; 252 | } 253 | 254 | .hide { 255 | display: none; 256 | } 257 | 258 | .h1 { 259 | font-size: 3rem; 260 | line-height: 1.15; 261 | } 262 | 263 | .h2 { 264 | font-size: 2.5rem; 265 | line-height: 1.2; 266 | } 267 | 268 | .h3 { 269 | font-size: 2rem; 270 | line-height: 1.25; 271 | } 272 | 273 | .text-center { 274 | text-align: center; 275 | } 276 | 277 | .normal { 278 | font-weight: 400; 279 | } 280 | 281 | .b { 282 | font-weight: bold; 283 | } 284 | 285 | .nm { 286 | margin-top: 0; 287 | } 288 | 289 | @media (min-width: 700px) { 290 | .wide, .play { 291 | margin-left: -3rem; 292 | margin-right: -3rem; 293 | } 294 | } 295 | 296 | @media (min-width: 700px) { 297 | 298 | .play { 299 | border: 3px solid #D6336C; 300 | border-radius: 5px; 301 | } 302 | 303 | .play.blue { 304 | border: 3px solid #3B5BDB; 305 | border-radius: 5px; 306 | } 307 | } 308 | 309 | 310 | 311 | /* 312 | 313 | CUSTOM BUTTON 314 | 315 | & 316 | 317 | CUSTOM FILE INPUT 318 | 319 | 320 | 321 | 322 | */ 323 | 324 | .custom-file-input { 325 | width: 0.1px; 326 | height: 0.1px; 327 | opacity: 0; 328 | overflow: hidden; 329 | position: absolute; 330 | z-index: -1; 331 | } 332 | 333 | .button, .custom-file-input + label { 334 | box-sizing: border-box; 335 | flex: 0 0 auto; 336 | display: inline-block; 337 | padding: .68rem 1.3rem; 338 | background-color: #111; 339 | border: 1px solid transparent; 340 | border-radius: 9999px; 341 | color: #FFFFFF; 342 | cursor: pointer; 343 | font-size: 1.25rem; 344 | font-weight: 500; 345 | line-height: 1.44; 346 | text-align: center; 347 | text-decoration: none #6B7280 solid; 348 | text-decoration-thickness: auto; 349 | transition-duration: .2s; 350 | transition-property: background-color,border-color,color,fill,stroke; 351 | transition-timing-function: cubic-bezier(.4, 0, 0.2, 1); 352 | user-select: none; 353 | -webkit-user-select: none; 354 | touch-action: manipulation; 355 | width: auto; 356 | } 357 | 358 | .button.small, .custom-file-input.small + label { 359 | padding: .45rem 1.08rem; 360 | font-size: 1rem; 361 | } 362 | 363 | .button *, .custom-file-input + label * { 364 | pointer-events: none; 365 | } 366 | 367 | .button:hover, .custom-file-input:focus + label, .custom-file-input + label:hover { 368 | background-color: #262626; 369 | } 370 | 371 | .button:focus, .custom-file-input:focus + label, .custom-file-input.has-focus + label { 372 | box-shadow: none; 373 | outline: 2px solid transparent; 374 | outline-offset: 2px; 375 | } 376 | 377 | 378 | 379 | /* details & summary */ 380 | 381 | details { 382 | box-sizing: border-box; 383 | border: 1px solid #000; 384 | border-radius: 4px; 385 | padding: .5em .5em 0; 386 | } 387 | 388 | details * { 389 | box-sizing: border-box; 390 | } 391 | 392 | summary { 393 | font-weight: bold; 394 | margin: -.5em -.5em 0; 395 | padding: .5em; 396 | cursor: pointer; 397 | } 398 | 399 | details[open] { 400 | padding: .5em; 401 | } 402 | 403 | details[open] summary { 404 | margin-bottom: .5em; 405 | } 406 | 407 | 408 | 409 | .download-assets { 410 | position: absolute; 411 | bottom: 16px; 412 | right: 36px; 413 | width: calc(158px * 1.18); 414 | height: calc(175px * 1.18); 415 | background: url(../images/download-assets.png) top left / cover no-repeat; 416 | } 417 | 418 | .download-assets:hover { 419 | opacity: .8; 420 | } 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | -------------------------------------------------------------------------------- /images/1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /images/2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /images/3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /images/animation-software.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panphora/animatize/224d881a9a87c287fb3a693951c95fdaa484f89a/images/animation-software.jpg -------------------------------------------------------------------------------- /images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panphora/animatize/224d881a9a87c287fb3a693951c95fdaa484f89a/images/bg.png -------------------------------------------------------------------------------- /images/boat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panphora/animatize/224d881a9a87c287fb3a693951c95fdaa484f89a/images/boat.png -------------------------------------------------------------------------------- /images/clicking-cursor.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /images/download-assets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panphora/animatize/224d881a9a87c287fb3a693951c95fdaa484f89a/images/download-assets.png -------------------------------------------------------------------------------- /images/instructions-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /images/instructions-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /images/instructions-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /images/instructions-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /images/instructions-5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /images/og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panphora/animatize/224d881a9a87c287fb3a693951c95fdaa484f89a/images/og.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Animatize - animations the easy way 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
48 |

Making animations the easy way

49 |

I’ve always dreamed of making animations, but the software is so complex...

50 | 51 |
52 |
What if you could make an animation...
53 |
...by dragging your mouse around?!
54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 |
62 |
63 |
64 |
65 |

Welcome to

66 |
67 |

Animatize

68 |
69 |

Make an animation by dragging a character around the screen

70 |
71 |
72 |

Try it out!

73 |
74 | 75 | 76 | 77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | 96 |
97 |
98 |
99 |
you can embed this animation
100 |
on your own website:
101 |
102 | 103 |
104 | 105 | 106 |

Copy and paste this code into your website where you want this animation to appear

107 |

It will load instantly and start playing!

108 |
109 |
110 |
111 |
112 |

Want to make one for your own website?

113 |
114 |
115 |

Make your own animation

116 |
117 | 118 |
Your canvas:
119 |
120 |
121 |
122 |
123 |
Your
character:
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | 140 |
141 |
142 |
143 | 144 |
145 |
Upload a background image
146 | 147 | 148 |
width: 800px, height: 480px
149 |
150 |
151 |
152 | 153 |
154 |
Upload a character image
155 | 156 | 157 |
width: 144px, height: 144px
158 |
159 |
160 |
161 | 162 |
163 |
Drag the character over the background
164 |
165 |
166 |
167 |
168 | 169 |
170 | 171 |

Add it to your own site!

172 |

Once you drag the character onto the canvas, the animation will start recording.

173 |

Once your finished, you can download the code and add it to your own site!

174 |
175 | 176 |
177 | 178 | 179 |

Copy and paste this code into your website where you want this animation to appear

180 |

It will load instantly and start playing!

181 |
182 |
183 |
Made by @panphora
184 |
185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | let characterElems = document.querySelectorAll(".character"); 2 | 3 | let animationOutputElems = document.querySelectorAll(".canvas[data-input-from]"); 4 | let animationInputElems = document.querySelectorAll(".canvas[data-output-to]"); 5 | let animationOutputElemsCount = animationOutputElems.length; 6 | 7 | let demoAnimationHistory = JSON.parse('[[-17.951171875,58.42773437499999],[-17.751953125,58.42773437499999],[-17.646484375,58.42773437499999],[-17.30078125,58.42773437499999],[-17.12890625,58.42773437499999],[-16.826171875,58.42773437499999],[-16.623046875,58.42773437499999],[-16.521484375,58.42773437499999],[-16.28125,58.42773437499999],[-16.216796875,58.42773437499999],[-15.9140625,58.42773437499999],[-15.609375,58.42773437499999],[-15.353515625,58.212890625],[-15.3046875,58.170572916666664],[-14.7421875,58.170572916666664],[-14.482421875000002,58.170572916666664],[-14.328125,58.040364583333336],[-14.179687499999998,57.91341145833333],[-13.91015625,57.91341145833333],[-13.662109375,57.91341145833333],[-13.3828125,57.75716145833333],[-13.14453125,57.62369791666667],[-12.855468749999998,57.4609375],[-12.626953125000002,57.33072916666667],[-12.333984375,57.33072916666667],[-12.109375,57.33072916666667],[-11.806640625,57.161458333333336],[-11.591796875,57.041015625],[-11.2890625,56.871744791666664],[-11.07421875,56.751302083333336],[-10.591796875,56.54947916666667],[-10.302734375,56.42578124999999],[-9.951171875,56.227213541666664],[-9.78515625,56.13281249999999],[-9.439453125,55.93749999999999],[-9.267578125,55.83984374999999],[-9.048828125,55.654296875],[-8.962890625,55.579427083333336],[-8.5625,55.579427083333336],[-8.4453125,55.579427083333336],[-8.20703125,55.37760416666667],[-8.140625,55.31901041666667],[-7.718750000000001,55.31901041666667],[-7.623046875,55.31901041666667],[-7.337890625,55.078125],[-7.320312499999999,55.061848958333336],[-7.025390625,54.81445312499999],[-7.015625,54.80468750000001],[-6.501953125,54.518229166666664],[-6.343749999999999,54.384765625],[-6.193359375,54.2578125],[-5.673828125,53.968098958333336],[-5.251953125,53.78906249999999],[-4.90234375,53.64257812499999],[-4.609375,53.31380208333333],[-4.384765625,53.059895833333336],[-3.9355468749999996,52.87109375],[-3.61328125,52.734375],[-3.310546875,52.565104166666664],[-3.095703125,52.44466145833333],[-2.603515625,52.236328125],[-2.32421875,52.11914062500001],[-1.9921874999999998,51.93359374999999],[-1.806640625,51.829427083333336],[-1.462890625,51.637369791666664],[-1.2890625,51.539713541666664],[-0.93359375,51.341145833333336],[-0.771484375,51.24999999999999],[-0.390625,51.24999999999999],[-0.25390625,51.24999999999999],[-0.0234375,51.05468749999999],[0.05078125,50.989583333333336],[0.462890625,50.989583333333336],[0.568359375,50.989583333333336],[0.87109375,50.989583333333336],[1.125,50.77473958333333],[1.173828125,50.732421875],[1.640625,50.732421875],[1.69140625,50.732421875],[1.986328125,50.48502604166667],[2.146484375,50.475260416666664],[2.30078125,50.475260416666664],[2.4609375,50.33854166666667],[2.60546875,50.21484375000001],[2.76953125,50.21484375000001],[2.908203125,50.21484375000001],[3.1894531249999996,50.21484375000001],[3.42578125,50.21484375000001],[3.599609375,50.06835937500001],[3.7304687500000004,49.957682291666664],[3.912109375,49.957682291666664],[4.03515625,49.957682291666664],[4.224609375,49.957682291666664],[4.337890625,49.957682291666664],[4.53125,49.794921875],[4.642578125,49.700520833333336],[4.9765625,49.700520833333336],[5.16015625,49.700520833333336],[5.3671875,49.524739583333336],[5.46484375,49.440104166666664],[5.841796875,49.440104166666664],[5.982421875,49.440104166666664],[6.208984375,49.248046875],[6.287109375,49.1796875],[6.806640625,49.1796875],[7.029296875,48.99088541666667],[7.109375,48.922526041666664],[7.37109375,48.922526041666664],[7.412109375000001,48.922526041666664],[7.8671875,48.922526041666664],[7.9296875,48.922526041666664],[8.2109375,48.684895833333336],[8.232421875,48.66536458333333],[8.724609375,48.66536458333333],[8.75,48.66536458333333],[9.052734375,48.66536458333333],[9.2109375,48.66536458333333],[9.357421875,48.66536458333333],[9.662109375,48.66536458333333],[9.828125,48.525390625],[9.966796875,48.408203125],[10.140625,48.408203125],[10.271484375,48.408203125],[10.5703125,48.408203125],[10.7890625,48.408203125],[11.1015625,48.232421875],[11.306640625,48.115234375],[11.498046875,48.115234375],[11.611328125,48.115234375],[11.955078125,48.115234375],[12.12890625,48.115234375],[12.474609375,47.919921875],[12.646484375,47.822265625],[13.177734375,47.822265625],[13.41796875,47.822265625],[13.802734375,47.607421875],[13.935546874999998,47.532552083333336],[14.249999999999998,47.532552083333336],[14.433593750000002,47.532552083333336],[14.861328125,47.291666666666664],[14.951171875,47.239583333333336],[15.605468750000002,47.239583333333336],[15.72265625,47.239583333333336],[16.158203125,47.239583333333336],[16.240234375,47.239583333333336],[16.7578125,47.239583333333336],[17.263671875,47.239583333333336],[17.53515625,47.093098958333336],[17.794921875,46.946614583333336],[18.568359375,46.946614583333336],[18.826171875,46.946614583333336],[19.080078125,46.946614583333336],[19.373046875,46.946614583333336],[19.59765625,46.946614583333336],[19.888671875,46.946614583333336],[20.115234375,46.946614583333336],[20.421875,46.946614583333336],[20.6328125,46.946614583333336],[21.40625,46.946614583333336],[21.708984375,46.946614583333336],[21.923828125,46.946614583333336],[22.263671875,46.946614583333336],[22.44140625,46.946614583333336],[22.796875,46.946614583333336],[22.958984375,46.946614583333336],[23.333984375,46.946614583333336],[23.4765625,46.946614583333336],[23.986328125,46.946614583333336],[24.5625,46.946614583333336],[24.7578125,46.946614583333336],[25.179687499999996,46.946614583333336],[25.277343749999996,46.946614583333336],[25.919921875,46.946614583333336],[26.048828125,46.946614583333336],[26.72265625,46.946614583333336],[26.822265625000004,46.946614583333336],[27.314453125,46.946614583333336],[28.017578124999996,46.946614583333336],[28.107421875,46.946614583333336],[28.865234375,46.946614583333336],[29.150390625,46.946614583333336],[29.396484375,46.946614583333336],[30.169921875,46.946614583333336],[30.941406249999996,46.946614583333336],[31.232421875,46.946614583333336],[31.458984375,46.946614583333336],[31.912109374999996,46.946614583333336],[32.23046875,46.946614583333336],[32.541015625,46.946614583333336],[32.748046875,46.946614583333336],[33.07421875,47.125651041666664],[33.265625,47.229817708333336],[33.603515625,47.415364583333336],[33.783203125,47.513020833333336],[34.5546875,47.83203125],[34.927734375,47.83203125],[35.072265625,47.83203125],[35.30078125,48.020833333333336],[35.376953125,48.082682291666664],[35.77734375,48.304036458333336],[35.89453125,48.369140625],[36.314453125,48.60026041666667],[36.412109375,48.65234375],[36.666015625,48.65234375],[36.71484375,48.65234375],[37.17578125,48.90625],[37.232421875,48.935546875],[37.521484375,49.176432291666664],[37.7890625,49.329427083333336],[38.0546875,49.475911458333336],[38.208984375,49.602864583333336],[38.357421875,49.7265625],[38.623046875,49.873046875],[38.875,50.013020833333336],[39.1796875,50.013020833333336],[39.34375,50.14973958333333],[39.484375,50.266927083333336],[39.65625,50.41015625000001],[39.7890625,50.520833333333336],[39.97265625,50.673828125],[40.09375,50.77473958333333],[40.3984375,51.02864583333333],[40.58203125,51.02864583333333],[40.703125,51.02864583333333],[41.373046875,51.442057291666664],[41.521484375,51.56575520833333],[41.826171875,51.819661458333336],[42.205078125,51.819661458333336],[42.34375,51.819661458333336],[43.06640625,52.3046875],[43.412109375,52.565104166666664],[43.46875,52.610677083333336],[43.904296875,52.85156250000001],[44.447265625,53.151041666666664],[44.50390625,53.18033854166667],[44.796875,53.42447916666667],[45.064453125,53.57421875],[45.328125,53.720703125],[45.6328125,53.97460937500001],[45.912109375,54.127604166666664],[46.150390625,54.2578125],[46.4375,54.417317708333336],[46.66796875,54.54427083333333],[46.83984375,54.54427083333333],[46.97265625,54.54427083333333],[47.15234375,54.69401041666667],[47.27734375,54.798177083333336],[47.5859375,54.967447916666664],[47.794921875,55.08138020833333],[47.9921875,55.24414062500001],[48.099609375,55.33203125],[48.296875,55.494791666666664],[48.404296875,55.582682291666664],[48.609375,55.582682291666664],[48.70703125,55.582682291666664],[48.921875,55.76171875],[49.009765625,55.833333333333336],[49.40234375,56.05143229166667],[49.52734375,56.119791666666664],[49.767578125,56.31835937500001],[49.830078125,56.370442708333336],[50.072265625,56.370442708333336],[50.134765625,56.370442708333336],[50.400390625,56.591796875],[50.439453125,56.624348958333336],[50.95703124999999,56.907552083333336],[51.41015625000001,57.28190104166667],[51.56640625,57.412109375],[51.720703125,57.53906250000001],[51.87109375,57.66276041666667],[52.14257812500001,57.66276041666667],[52.388671875,57.66276041666667],[52.55664062499999,57.802734375],[52.69335937500001,57.91666666666667],[52.99804687500001,58.170572916666664],[53.517578125,58.45703125],[53.685546875,58.45703125],[53.818359375,58.45703125],[54.00390625,58.610026041666664],[54.123046875,58.707682291666664],[54.642578125,58.994140625],[54.947265625,59.24804687500001],[55.15820312500001,59.24804687500001],[55.251953125,59.24804687500001],[55.47265625,59.24804687500001],[55.556640625,59.24804687500001],[55.79296875000001,59.44335937500001],[55.861328125,59.498697916666664],[56.166015625,59.498697916666664],[56.396484375,59.690755208333336],[56.470703125,59.752604166666664],[56.923828125,59.752604166666664],[56.98828124999999,59.752604166666664],[57.24609375000001,59.752604166666664],[57.56640625,59.752604166666664],[57.595703125,59.752604166666664],[58.095703125,60.02929687500001],[58.267578125,60.03906249999999],[58.41796875000001,60.03906249999999],[58.72265625000001,60.29296875],[59.2421875,60.29296875],[59.412109375,60.29296875],[59.546875,60.29296875],[59.72460937500001,60.439453125],[59.849609375,60.54361979166667],[60.033203125,60.54361979166667],[60.15234375,60.54361979166667],[60.337890625,60.54361979166667],[60.45507812499999,60.54361979166667],[60.78125,60.54361979166667],[60.97265625,60.54361979166667],[61.177734375,60.71289062500001],[61.27734375,60.79427083333333],[61.48828125,60.79427083333333],[61.58007812500001,60.79427083333333],[61.673828125,60.79427083333333],[61.71093749999999,60.79427083333333],[61.9375,60.98307291666667],[62.015625,61.048177083333336],[62.251953125,61.048177083333336],[62.3203125,61.048177083333336],[62.57812499999999,61.048177083333336],[62.625,61.048177083333336],[62.892578125,61.048177083333336],[62.9296875,61.048177083333336],[63.20312500000001,61.048177083333336],[63.234375,61.048177083333336],[63.52734375,61.292317708333336],[63.5390625,61.302083333333336],[63.841796875,61.302083333333336],[64,61.42903645833333],[64.150390625,61.55273437499999],[64.41796875,61.55273437499999],[64.66796875,61.55273437499999],[64.830078125,61.55273437499999],[64.97265625,61.55273437499999],[65.1484375,61.55273437499999],[65.27734375,61.55273437499999],[65.794921875,61.839192708333336],[65.974609375,61.839192708333336],[66.09765625,61.839192708333336],[66.427734375,61.839192708333336],[66.615234375,61.839192708333336],[66.81640625,62.00520833333333],[66.919921875,62.08984374999999],[67.267578125,62.08984374999999],[67.4375,62.08984374999999],[67.7890625,62.08984374999999],[67.955078125,62.08984374999999],[68.341796875,62.08984374999999],[68.47265625,62.08984374999999],[68.876953125,62.314453125],[68.990234375,62.376302083333336],[69.228515625,62.376302083333336],[69.29296875,62.376302083333336],[69.724609375,62.376302083333336],[69.810546875,62.376302083333336],[70.24609375,62.376302083333336],[70.328125,62.376302083333336],[70.60546875,62.376302083333336],[70.630859375,62.376302083333336],[71.123046875,62.376302083333336],[71.1484375,62.376302083333336],[71.658203125,62.376302083333336],[72.0546875,62.376302083333336],[72.439453125,62.376302083333336],[72.958984375,62.376302083333336],[73.244140625,62.376302083333336],[73.4765625,62.376302083333336],[73.7578125,62.376302083333336],[73.9921875,62.376302083333336],[74.2890625,62.376302083333336],[74.509765625,62.376302083333336],[74.693359375,62.376302083333336],[74.8125,62.376302083333336],[75.130859375,62.376302083333336],[75.330078125,62.376302083333336],[75.529296875,62.376302083333336],[75.634765625,62.376302083333336],[75.841796875,62.376302083333336],[75.939453125,62.376302083333336],[76.1484375,62.376302083333336],[76.244140625,62.376302083333336],[76.46875,62.376302083333336],[76.546875,62.376302083333336],[76.7734375,62.376302083333336],[76.8515625,62.376302083333336],[77.091796875,62.174479166666664],[77.15625,62.119140625],[77.412109375,62.119140625],[77.4609375,62.119140625],[77.732421875,61.891276041666664],[77.763671875,61.86197916666667],[78.04296875,61.86197916666667],[78.068359375,61.86197916666667],[78.359375,61.61783854166667],[78.5234375,61.604817708333336],[78.677734375,61.604817708333336],[78.8359375,61.47135416666667],[78.98046875,61.34765625000001],[79.14453125,61.34765625000001],[79.28515625,61.34765625000001],[79.453125,61.204427083333336],[79.587890625,61.09049479166667],[79.75,61.09049479166667],[79.888671875,61.09049479166667],[80.0625,60.94401041666667],[80.193359375,60.83333333333333],[80.37890625,60.83333333333333],[80.498046875,60.83333333333333],[80.828125,60.64778645833333],[81.015625,60.54036458333333],[81.21484375,60.54036458333333],[81.318359375,60.54036458333333],[81.525390625,60.364583333333336],[81.623046875,60.279947916666664],[81.84375,60.279947916666664],[81.927734375,60.279947916666664],[82.158203125,60.084635416666664],[82.23046875,60.022786458333336],[82.470703125,60.022786458333336],[82.53515625,60.022786458333336],[82.76171875,59.830729166666664],[82.837890625,59.765625],[83.08984375,59.554036458333336],[83.142578125,59.508463541666664],[83.59375,59.508463541666664],[83.93359375,59.27734375],[83.962890625,59.251302083333336],[84.44921875,59.251302083333336],[84.482421875,59.251302083333336],[84.787109375,58.994140625],[85.302734375,58.704427083333336],[85.580078125,58.54817708333333],[85.82421875,58.411458333333336],[85.9921875,58.268229166666664],[86.12890625,58.15104166666667],[86.423828125,58.15104166666667],[86.646484375,58.15104166666667],[87.1640625,57.861328125],[87.474609375,57.68554687500001],[87.681640625,57.568359375],[87.869140625,57.408854166666664],[87.984375,57.311197916666664],[88.330078125,57.115885416666664],[88.501953125,57.018229166666664],[88.849609375,56.822916666666664],[89.01953125,56.725260416666664],[89.236328125,56.54296875],[89.32421875,56.468098958333336],[89.697265625,56.468098958333336],[89.841796875,56.468098958333336],[90.080078125,56.266276041666664],[90.14453125,56.2109375],[90.390625,56.00260416666667],[90.44921875,55.95052083333333],[90.708984375,55.73242187500001],[90.75390625,55.69335937499999],[90.87109375,55.69335937499999],[90.884765625,55.69335937499999],[91.1640625,55.458984375],[91.3359375,55.3125],[91.49609375,55.17578125],[91.65234375,55.17578125],[91.80078125,55.17578125],[92.072265625,55.02278645833333],[92.318359375,54.8828125],[92.48046875,54.74609375],[92.623046875,54.625651041666664],[93.142578125,54.3359375],[93.302734375,54.19921875],[93.4453125,54.078776041666664],[93.623046875,53.929036458333336],[93.75,53.821614583333336],[94.26953125,53.531901041666664],[94.44140625,53.385416666666664],[94.572265625,53.27473958333333],[94.91015625,53.0859375],[95.08984375,52.98502604166667],[95.298828125,52.809244791666664],[95.39453125,52.72786458333333],[95.9140625,52.43815104166667],[96.14453125,52.24283854166667],[96.21875,52.17773437499999],[96.62109375,52.17773437499999],[96.736328125,52.17773437499999],[97.146484375,51.94661458333333],[97.25390625,51.88476562499999],[97.6875,51.64062499999999],[97.771484375,51.59179687499999],[98.244140625,51.328125],[98.291015625,51.29882812499999],[98.767578125,51.03190104166667],[99.287109375,51.00585937499999],[99.326171875,51.00585937499999],[99.814453125,50.732421875]]'); 8 | 9 | // file inputs 10 | let backgroundImageInputElem = document.querySelector("[name='background-image']"); 11 | let characterImageInputElem = document.querySelector("[name='character-image']"); 12 | 13 | let demoDotsHTML = ''; 14 | let demoCanvasInner = document.querySelector(".canvas.full.demo .canvas-inner"); 15 | demoCanvasInner.insertAdjacentHTML("afterbegin", demoDotsHTML); 16 | 17 | // // for generating demo dots: 18 | // let demoDotsHTML = ""; 19 | // demoAnimationHistory.forEach((coord, index) => { 20 | // if (index % 7 === 0) { 21 | // demoDotsHTML += ``; 22 | // } 23 | // }); 24 | // demoCanvasInner.insertAdjacentHTML("afterbegin", demoDotsHTML); 25 | // document.addEventListener("click", (e) => e.target.remove()); 26 | 27 | function init () { 28 | animationOutputElems.forEach(el => { 29 | let animationInputElemSelector = `[data-output-to="${el.getAttribute("data-input-from")}"]`; 30 | el.animationInputElem = document.querySelector(animationInputElemSelector); 31 | el.isAnimationOutputElem = true; 32 | el.characterContainerElem = el.querySelector(".character-container"); 33 | el.backgroundElem = el.querySelector(".canvas-inner"); 34 | el.characterElem = el.querySelector(".character-inner"); 35 | 36 | el.animationHistory = []; 37 | el.animationIndex = 0; 38 | }); 39 | 40 | animationInputElems.forEach(el => { 41 | let animationOutputElemSelector = `[data-input-from="${el.getAttribute("data-output-to")}"]`; 42 | el.animationOutputElem = document.querySelector(animationOutputElemSelector); 43 | el.isAnimationInputElem = true; 44 | }); 45 | 46 | characterElems.forEach(el => { 47 | el.animationContainerElem = el.closest(".canvas"); 48 | el.animationContainerElem.characterElem = el; 49 | 50 | if (el.animationContainerElem.isAnimationInputElem) { 51 | el.animationOutputElem = el.animationContainerElem.animationOutputElem; 52 | } else { 53 | el.animationInputElem = el.animationContainerElem.animationInputElem; 54 | } 55 | 56 | el.backgroundElem = el.animationContainerElem.querySelector(".canvas-inner"); 57 | el.positionX = 0; 58 | el.positionY = 0; 59 | el.throttleMovementIndex = 0; 60 | }); 61 | 62 | let demoAnimationOutputElem = document.querySelector('[data-input-from="demo"]'); 63 | demoAnimationOutputElem.animationHistory = demoAnimationHistory; 64 | } 65 | 66 | init(); 67 | 68 | 69 | interact('.draggable').draggable({ 70 | listeners: { 71 | start (event) { 72 | let playElem = event.target.closest(".play"); 73 | if (playElem) { 74 | playElem.classList.add("drag-started"); 75 | } 76 | }, 77 | move (event) { 78 | let characterElem = event.currentTarget; 79 | let backgroundElem = characterElem.backgroundElem; 80 | 81 | characterElem.positionX += event.dx; 82 | characterElem.positionY += event.dy; 83 | 84 | characterElem.style.transform = `translate(${characterElem.positionX}px, ${characterElem.positionY}px)`; 85 | 86 | 87 | let characterRect = interact.getElementRect(characterElem); 88 | let backgroundRect = interact.getElementRect(backgroundElem); 89 | 90 | if (doesCollide(characterRect, backgroundRect)) { 91 | // don't record every movement to save space 92 | let throttleMovementIndex = characterElem.throttleMovementIndex; 93 | 94 | if (throttleMovementIndex % 2 === 0) { 95 | // make character movement relative to background 96 | let leftPercentage = ((characterRect.left - backgroundRect.left) / backgroundRect.width) * 100; 97 | let topPercentage = ((characterRect.top - backgroundRect.top) / backgroundRect.height) * 100; 98 | characterElem.animationOutputElem.animationHistory.push([leftPercentage, topPercentage]); 99 | } 100 | 101 | throttleMovementIndex++; 102 | } 103 | }, 104 | } 105 | }) 106 | 107 | 108 | 109 | 110 | 111 | function gameLoop() { 112 | 113 | // loop through the animation output elements 114 | for (let i = 0; i < animationOutputElemsCount; i++) { 115 | let animationOutputElem = animationOutputElems[i]; 116 | 117 | if (animationOutputElem.animationHistory.length !== 0) { 118 | if (animationOutputElem.animationIndex === animationOutputElem.animationHistory.length) { 119 | animationOutputElem.animationIndex = 0; 120 | } 121 | 122 | let currentTranslation = animationOutputElem.animationHistory[animationOutputElem.animationIndex]; 123 | animationOutputElem.characterElem.classList.remove("hide"); 124 | 125 | animationOutputElem.characterContainerElem.style.transform = `translate(${currentTranslation[0]}%, ${currentTranslation[1]}%)`; 126 | animationOutputElem.animationIndex++; 127 | } 128 | 129 | } 130 | 131 | window.requestAnimationFrame(gameLoop); 132 | } 133 | 134 | gameLoop(); 135 | 136 | 137 | let userAnimationPlayContainer = document.querySelector('[data-has-character][data-has-background]'); 138 | let characterBackgroundImageStylesheet = document.querySelector("#character-background-image"); 139 | let backgroundBackgroundImageStylesheet = document.querySelector("#background-background-image"); 140 | let characterBackgroundImageElem = document.querySelector(".user-character-image"); 141 | let backgroundBackgroundImageElem = document.querySelector(".user-background-image"); 142 | let customFileInputs = document.querySelectorAll(".custom-file-input"); 143 | customFileInputs.forEach((customFileInput) => { 144 | customFileInput.addEventListener("change", (event) => { 145 | let file = customFileInput.files[0]; 146 | 147 | if ( /\.(jpe?g|png|gif)$/i.test(file.name) ) { 148 | let reader = new FileReader(); 149 | 150 | reader.addEventListener("load", function () { 151 | customFileInput.nextElementSibling.innerText = file.name; 152 | 153 | if (customFileInput.id === "backgroundImage") { 154 | backgroundBackgroundImageStylesheet.innerHTML = ".user-background-image {background-image: url(" + reader.result + ") !important;}"; 155 | userAnimationPlayContainer.setAttribute("data-has-background", "true"); 156 | } 157 | 158 | if (customFileInput.id === "characterImage") { 159 | characterBackgroundImageStylesheet.innerHTML = ".user-character-image {background-image: url(" + reader.result + ") !important;}"; 160 | userAnimationPlayContainer.setAttribute("data-has-character", "true"); 161 | } 162 | 163 | if (userAnimationPlayContainer.getAttribute("data-has-background") === "true" && userAnimationPlayContainer.getAttribute("data-has-character") === "true") { 164 | userAnimationPlayContainer.classList.remove("hide-user-animations"); 165 | } 166 | }, false); 167 | 168 | reader.readAsDataURL(file); 169 | } 170 | }); 171 | }); 172 | 173 | 174 | // UTILS 175 | 176 | function doesCollide (elemPos1, elemPos2) { 177 | return elemPos1.left < elemPos2.left + elemPos2.width 178 | && elemPos1.left + elemPos1.width > elemPos2.left 179 | && elemPos1.top < elemPos2.top + elemPos2.height 180 | && elemPos1.height + elemPos1.top > elemPos2.top; 181 | } 182 | 183 | 184 | // clipboard 185 | 186 | let clipboard = new ClipboardJS('.copy-code'); 187 | clipboard.on('success', function () { 188 | crostini("Code successfully copied!"); 189 | }); 190 | 191 | 192 | 193 | // FIXES 194 | 195 | // fix firefox bug, see: https://tympanus.net/codrops/2015/09/15/styling-customizing-file-inputs-smart-way/ 196 | document.querySelectorAll(".custom-file-input").forEach(inputElem => { 197 | inputElem.addEventListener("focus", () => { inputElem.classList.add("has-focus") }); 198 | inputElem.addEventListener("blur", () => { inputElem.classList.remove("has-focus") }); 199 | }); 200 | 201 | 202 | 203 | let baseCSS = ` 204 | .canvas { 205 | position: relative; 206 | left: 120px; 207 | max-width: 200px; 208 | } 209 | 210 | .canvas-inner { 211 | width: 100%; 212 | padding-top: 60%; 213 | background-position: top left; 214 | background-size: cover; 215 | background-repeat: no-repeat; 216 | } 217 | 218 | .character-container { 219 | position: absolute; 220 | top: 0; 221 | left: 0; 222 | width: 100%; 223 | height: 100%; 224 | } 225 | 226 | .character { 227 | position: absolute; 228 | top: 42px; 229 | left: -60px; 230 | width: 18%; 231 | } 232 | 233 | .character-inner { 234 | width: 100%; 235 | padding-top: 100%; 236 | background-position: top left; 237 | background-size: cover; 238 | background-repeat: no-repeat; 239 | } 240 | 241 | .canvas.full { 242 | overflow: hidden; /* to hide character when it's out of frame */ 243 | left: 0; 244 | max-width: 100%; 245 | } 246 | 247 | .canvas.full .character { 248 | top: 0; 249 | left: 0; 250 | }`; 251 | 252 | let baseHTML = ` 253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 | `; 263 | 264 | function generateCode (sourceElem, isDemo) { 265 | let animationHistory = sourceElem.animationHistory; 266 | 267 | if (!isDemo && backgroundBackgroundImageStylesheet.innerHTML.length === 0) { 268 | crostini("Upload a background first!" , {type: "error"}); 269 | return; 270 | } 271 | 272 | if (!isDemo && characterBackgroundImageStylesheet.innerHTML.length === 0) { 273 | crostini("Upload a character first!" , {type: "error"}); 274 | return; 275 | } 276 | 277 | if (animationHistory.length === 0) { 278 | crostini("Drag character to animate first" , {type: "error"}); 279 | return; 280 | } 281 | 282 | let combinedCSS; 283 | if (!isDemo) { 284 | combinedCSS = ""; 285 | } else { 286 | let demoBackgroundImageStylesheet = document.querySelector("#demo-background-images"); 287 | combinedCSS = ""; 288 | } 289 | 290 | let baseJS = ` 291 | 314 | `; 315 | 316 | let outputtedCode = combinedCSS + baseHTML + baseJS; 317 | return outputtedCode; 318 | } 319 | 320 | 321 | document.querySelectorAll(".generate-code").forEach(generateCodeElem => { 322 | generateCodeElem.addEventListener("click", (event) => { 323 | let codePlaygroundElem = event.target.closest(".code-playground"); 324 | let codeContainer = codePlaygroundElem.querySelector(".code-container"); 325 | 326 | let sourceElemSelector = event.currentTarget.getAttribute("data-animation-history-elem-selector"); 327 | let sourceElem = document.querySelector(sourceElemSelector); 328 | let isDemo = event.currentTarget.getAttribute("data-is-demo") === "true"; 329 | 330 | let generatedCode = generateCode(sourceElem, isDemo); 331 | 332 | if (generatedCode) { 333 | codeContainer.querySelector(".code").value = generatedCode; 334 | codeContainer.classList.remove("hide"); 335 | } 336 | }); 337 | }); 338 | 339 | 340 | document.querySelectorAll(".reset-animation").forEach(resetAnimationElem => { 341 | resetAnimationElem.addEventListener("click", (event) => { 342 | let playElem = event.target.closest(".play"); 343 | let _userAnimationOutputElem = playElem.querySelector("[data-input-from]"); 344 | let _userAnimationInputElem = playElem.querySelector("[data-output-to]"); 345 | let outputCharacterElem = _userAnimationOutputElem.querySelector(".character"); 346 | let inputCharacterElem = _userAnimationInputElem.querySelector(".character"); 347 | let codePlaygroundSelector = event.currentTarget.getAttribute("data-code-playground-selector"); 348 | let codePlaygroundElem = document.querySelector(codePlaygroundSelector); 349 | let codeContainer = codePlaygroundElem.querySelector(".code-container"); 350 | 351 | // clear generated code 352 | codeContainer.querySelector(".code").value = ""; 353 | // hide generated code 354 | codeContainer.classList.add("hide"); 355 | // erase history on user canvas element 356 | _userAnimationOutputElem.animationHistory = []; 357 | // remove drag-started class 358 | playElem.classList.remove("drag-started"); 359 | // reset animation index 360 | _userAnimationOutputElem.animationIndex = 0; 361 | // hide output character 362 | outputCharacterElem.classList.add("hide"); 363 | // reset input character position 364 | inputCharacterElem.style.transform = `translate(0px, 0px)`; 365 | // reset relative position data on character elem 366 | inputCharacterElem.positionX = 0; 367 | inputCharacterElem.positionY = 0; 368 | // success message! 369 | crostini("Animation successfully reset"); 370 | }); 371 | }); 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "motion-comic-builder", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT" 11 | } 12 | --------------------------------------------------------------------------------