├── README.md ├── index.html ├── script.js └── style.css /README.md: -------------------------------------------------------------------------------- 1 | # parallax-scroll-animation 2 | 3 | # Technologies used 4 | 5 | * HTML 6 | * CSS 7 | * JavaScript 8 | 9 | ## Live website can be viewed here 10 | 11 | https://peter-kimanzi.github.io/parallax-scroll-animation/ 12 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Parallax scroll animation 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 51 | 52 | 53 | 54 | 55 | 57 | 58 | 59 | 60 | 61 | 62 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 108 | 109 | 110 | 111 | 113 | 115 | 117 | 118 | 119 | 120 | 121 | 122 | 124 | 125 | 127 | 128 | 130 | 131 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 144 | 147 | 150 | 153 | 156 | 157 | 158 | 159 | 162 | 165 | 168 | 171 | 174 | 176 | 177 | 178 | 179 | 180 | 181 | 292 | 293 | 294 | 295 | 296 | 297 | 300 | 303 | 306 | 309 | 312 | 315 | 316 | 317 | 318 | 319 | 322 | 325 | 328 | 331 | 332 | 333 | 334 | 335 |
336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | gsap.registerPlugin(ScrollTrigger); 2 | let speed = 100; 3 | 4 | /* SCENE 1 */ 5 | let scene1 = gsap.timeline(); 6 | ScrollTrigger.create({ 7 | animation: scene1, 8 | trigger: ".scrollElement", 9 | start: "top top", 10 | end: "45% 100%", 11 | scrub: 3, 12 | }); 13 | 14 | // hills animation 15 | scene1.to("#h1-1", { y: 3 * speed, x: 1 * speed, scale: 0.9, ease: "power1.in" }, 0) 16 | scene1.to("#h1-2", { y: 2.6 * speed, x: -0.6 * speed, ease: "power1.in" }, 0) 17 | scene1.to("#h1-3", { y: 1.7 * speed, x: 1.2 * speed }, 0.03) 18 | scene1.to("#h1-4", { y: 3 * speed, x: 1 * speed }, 0.03) 19 | scene1.to("#h1-5", { y: 2 * speed, x: 1 * speed }, 0.03) 20 | scene1.to("#h1-6", { y: 2.3 * speed, x: -2.5 * speed }, 0) 21 | scene1.to("#h1-7", { y: 5 * speed, x: 1.6 * speed }, 0) 22 | scene1.to("#h1-8", { y: 3.5 * speed, x: 0.2 * speed }, 0) 23 | scene1.to("#h1-9", { y: 3.5 * speed, x: -0.2 * speed }, 0) 24 | 25 | //animate text 26 | scene1.to("#info", { y: 8 * speed }, 0) 27 | 28 | 29 | 30 | /* Bird */ 31 | gsap.fromTo("#bird", { opacity: 1 }, { 32 | y: -250, 33 | x: 800, 34 | ease: "power2.out", 35 | scrollTrigger: { 36 | trigger: ".scrollElement", 37 | start: "15% top", 38 | end: "60% 100%", 39 | scrub: 4, 40 | onEnter: function() { gsap.to("#bird", { scaleX: 1, rotation: 0 }) }, 41 | onLeave: function() { gsap.to("#bird", { scaleX: -1, rotation: -15 }) }, 42 | } 43 | }) 44 | 45 | 46 | /* Clouds */ 47 | let clouds = gsap.timeline(); 48 | ScrollTrigger.create({ 49 | animation: clouds, 50 | trigger: ".scrollElement", 51 | start: "top top", 52 | end: "70% 100%", 53 | scrub: 1, 54 | }); 55 | 56 | clouds.to("#cloud1", { x: 500 }, 0) 57 | clouds.to("#cloud2", { x: 1000 }, 0) 58 | clouds.to("#cloud3", { x: -1000 }, 0) 59 | clouds.to("#cloud4", { x: -700, y: 25 }, 0) 60 | 61 | 62 | 63 | /* Sun motion Animation */ 64 | let sun = gsap.timeline(); 65 | ScrollTrigger.create({ 66 | animation: sun, 67 | trigger: ".scrollElement", 68 | start: "top top", 69 | end: "2200 100%", 70 | scrub: 1, 71 | }); 72 | 73 | //sun motion 74 | sun.to("#bg_grad", { attr: { cy: "330" } }, 0.00) 75 | 76 | //bg change 77 | sun.to("#sun", { attr: { offset: "0.15" } }, 0.00) 78 | sun.to("#bg_grad stop:nth-child(2)", { attr: { offset: "0.15" } }, 0.00) 79 | sun.to("#bg_grad stop:nth-child(3)", { attr: { offset: "0.18" } }, 0.00) 80 | sun.to("#bg_grad stop:nth-child(4)", { attr: { offset: "0.25" } }, 0.00) 81 | sun.to("#bg_grad stop:nth-child(5)", { attr: { offset: "0.46" } }, 0.00) 82 | sun.to("#bg_grad stop:nth-child(6)", { attr: { "stop-color": "#FF9171" } }, 0) 83 | 84 | 85 | 86 | /* SCENE 2 */ 87 | let scene2 = gsap.timeline(); 88 | ScrollTrigger.create({ 89 | animation: scene2, 90 | trigger: ".scrollElement", 91 | start: "15% top", 92 | end: "40% 100%", 93 | scrub: 4, 94 | }); 95 | 96 | scene2.fromTo("#h2-1", { y: 500, opacity: 0 }, { y: 0, opacity: 1 }, 0) 97 | scene2.fromTo("#h2-2", { y: 500 }, { y: 0 }, 0.1) 98 | scene2.fromTo("#h2-3", { y: 700 }, { y: 0 }, 0.1) 99 | scene2.fromTo("#h2-4", { y: 700 }, { y: 0 }, 0.2) 100 | scene2.fromTo("#h2-5", { y: 800 }, { y: 0 }, 0.3) 101 | scene2.fromTo("#h2-6", { y: 900 }, { y: 0 }, 0.3) 102 | 103 | 104 | 105 | /* Bats */ 106 | gsap.fromTo("#bats", { opacity: 1, y: 400, scale: 0 }, { 107 | y: 120, 108 | scale: 0.8, 109 | transformOrigin: "50% 50%", 110 | ease: "power3.out", 111 | scrollTrigger: { 112 | trigger: ".scrollElement", 113 | start: "40% top", 114 | end: "70% 100%", 115 | scrub: 3, 116 | onEnter: function() { 117 | gsap.utils.toArray("#bats path").forEach((item, i) => { 118 | gsap.to(item, { scaleX: 0.5, yoyo: true, repeat: 11, duration: 0.15, delay: 0.7 + (i / 10), transformOrigin: "50% 50%" }) 119 | }); 120 | gsap.set("#bats", { opacity: 1 }) 121 | }, 122 | onLeave: function() { gsap.to("#bats", { opacity: 0, delay: 2 }) }, 123 | } 124 | }) 125 | 126 | 127 | /* Sun increase */ 128 | let sun2 = gsap.timeline(); 129 | ScrollTrigger.create({ 130 | animation: sun2, 131 | trigger: ".scrollElement", 132 | start: "2200 top", 133 | end: "5000 100%", 134 | scrub: 1, 135 | }); 136 | 137 | sun2.to("#sun", { attr: { offset: "0.6" } }, 0) 138 | sun2.to("#bg_grad stop:nth-child(2)", { attr: { offset: "0.7" } }, 0) 139 | sun2.to("#sun", { attr: { "stop-color": "#ffff00" } }, 0) 140 | sun2.to("#lg4 stop:nth-child(1)", { attr: { "stop-color": "#623951" } }, 0) 141 | sun2.to("#lg4 stop:nth-child(2)", { attr: { "stop-color": "#261F36" } }, 0) 142 | sun2.to("#bg_grad stop:nth-child(6)", { attr: { "stop-color": "#45224A" } }, 0) 143 | 144 | 145 | 146 | /* Transition (from Scene2 to Scene3) */ 147 | gsap.set("#scene3", { y: 580, visibility: "visible" }) 148 | let sceneTransition = gsap.timeline(); 149 | ScrollTrigger.create({ 150 | animation: sceneTransition, 151 | trigger: ".scrollElement", 152 | start: "70% top", 153 | end: "bottom 100%", 154 | scrub: 3, 155 | }); 156 | 157 | sceneTransition.to("#h2-1", { y: -680, scale: 1.5, transformOrigin: "50% 50%" }, 0) 158 | sceneTransition.to("#bg_grad", { attr: { cy: "-80" } }, 0.00) 159 | sceneTransition.to("#bg2", { y: 0 }, 0) 160 | 161 | 162 | 163 | /* Scene 3 */ 164 | let scene3 = gsap.timeline(); 165 | ScrollTrigger.create({ 166 | animation: scene3, 167 | trigger: ".scrollElement", 168 | start: "80% 50%", 169 | end: "bottom 100%", 170 | scrub: 3, 171 | }); 172 | 173 | //Hills motion 174 | scene3.fromTo("#h3-1", { y: 300 }, { y: -550 }, 0) 175 | scene3.fromTo("#h3-2", { y: 800 }, { y: -550 }, 0.03) 176 | scene3.fromTo("#h3-3", { y: 600 }, { y: -550 }, 0.06) 177 | scene3.fromTo("#h3-4", { y: 800 }, { y: -550 }, 0.09) 178 | scene3.fromTo("#h3-5", { y: 1000 }, { y: -550 }, 0.12) 179 | 180 | //stars 181 | scene3.fromTo("#stars", { opacity: 0 }, { opacity: 0.5, y: -500 }, 0) 182 | 183 | // Scroll Back text 184 | scene3.fromTo("#arrow2", { opacity: 0 }, { opacity: 0.7, y: -710 }, 0.25) 185 | scene3.fromTo("#text2", { opacity: 0 }, { opacity: 0.7, y: -710 }, 0.3) 186 | 187 | //gradient value change 188 | scene3.to("#bg2-grad", { attr: { cy: 600 } }, 0) 189 | scene3.to("#bg2-grad", { attr: { r: 500 } }, 0) 190 | 191 | 192 | /* falling star */ 193 | gsap.to("#fstar", { 194 | x: -700, 195 | y: -250, 196 | ease: "power4.out", 197 | scrollTrigger: { 198 | trigger: ".scrollElement", 199 | start: "4000 top", 200 | end: "6000 100%", 201 | scrub: 5, 202 | onEnter: function() { gsap.set("#fstar", { opacity: 1 }) }, 203 | onLeave: function() { gsap.set("#fstar", { opacity: 0 }) }, 204 | } 205 | }) 206 | 207 | 208 | //reset scrollbar position after refresh 209 | window.onbeforeunload = function() { 210 | window.scrollTo(0, 0); 211 | } 212 | 213 | 214 | let fullscreen; 215 | let fsEnter = document.getElementById('fullscr'); 216 | fsEnter.addEventListener('click', function (e) { 217 | e.preventDefault(); 218 | if (!fullscreen) { 219 | fullscreen = true; 220 | document.documentElement.requestFullscreen(); 221 | fsEnter.innerHTML = "Exit Fullscreen"; 222 | } 223 | else { 224 | fullscreen = false; 225 | document.exitFullscreen(); 226 | fsEnter.innerHTML = "Go Fullscreen"; 227 | } 228 | }); -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | body, 2 | html{ 3 | margin: 0; 4 | padding: 0; 5 | height: 100%; 6 | } 7 | 8 | /* Hide scrollbar for Chrome, Safari and Opera */ 9 | body::-webkit-scrollbar { 10 | display: none; 11 | } 12 | 13 | /* Hide scrollbar for IE, Edge and Firefox */ 14 | body { 15 | -ms-overflow-style: none; /* IE and Edge */ 16 | scrollbar-width: none; /* Firefox */ 17 | } 18 | 19 | svg { 20 | display: block; 21 | width: 100%; 22 | height: 100vh; 23 | position: fixed; 24 | top: 0; 25 | left: 0; 26 | } 27 | 28 | .scrollElement { 29 | position: absolute; 30 | height: 6000px; 31 | width: 100px; 32 | top: 0; 33 | z-index: 0; 34 | } 35 | 36 | .btn { 37 | position: fixed; 38 | bottom: 5%; 39 | right: 0px; 40 | transform: translateX(-50%); 41 | border: 1px solid #fff; 42 | border-radius: 5px; 43 | font-size: 0.9rem; 44 | padding: 0.5rem 0.7em; 45 | background-color: transparent; 46 | color: #ffffff; 47 | font-family: Verdana, Geneva, Tahoma, sans-serif; 48 | -webkit-font-smoothing: antialiased; 49 | cursor: pointer; 50 | transition: all .3s; 51 | z-index: 11; 52 | } 53 | 54 | .btn_works { 55 | left: 100px; 56 | right: unset; 57 | text-decoration: none; 58 | } 59 | 60 | .btn:hover { 61 | background: #ffffff; 62 | color: #1B1734; 63 | } --------------------------------------------------------------------------------