diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fe3a155 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + commit-message: + prefix: "chore" + - package-ecosystem: "github-actions" + directory: "/" + commit-message: + prefix: "chore" + schedule: + interval: "monthly" diff --git a/Challenges/Day 01 - JavaScript Drum Kit/index.html b/Challenges/Day 01 - JavaScript Drum Kit/index.html index 9176ae7..0a97996 100644 --- a/Challenges/Day 01 - JavaScript Drum Kit/index.html +++ b/Challenges/Day 01 - JavaScript Drum Kit/index.html @@ -1,97 +1,208 @@ + - JS Drum Kit - + + + + + JavaScript Drum Kit | JavaScript30 | @palashmon + + +
+
+
+

JavaScript Drum Kit

+

Press key or press space to play auto drum

+
+
+
+
+
+ A + clap +
+
+ S + hihat +
+
+ D + kick +
+
+ F + openhat +
+
+ G + boom +
+
+ H + ride +
+
+ J + snare +
+
+ K + tom +
+
+ L + tink +
+
+ + + + + + + + + +
+ +
+ + /************************************************************************************************ + Play some auto drum notes + ************************************************************************************************/ + let playing = false; + let interval; + const totalSteps = 16; + let currentStep = 1; + let fullSteps = Array.from({ length: 16 }, () => []); + const kick = 68; + const hihat = 83; + const snare = 74; + const tink = 76; + let bpm = 12; // increase or decrease this 12 param to see change in beats per minute + let count = 0; + + // Add the click event listener to our play button + const playAudioButton = document.querySelector('#playAudioButton'); + playAudioButton.addEventListener('click', play); + + // Toggle the play button and start/stop the audio based on current state + function play(e) { + playAudioButton.value = playing ? 'Start Audio' : 'Stop Audio'; + if (playing) { + stopAudio(); + } else { + startAudio(); + } + playing = !playing; + } + + // Play the instrument that is set for current step + function playStep(step) { + return Array.from(fullSteps[step]).map((keyCode) => playSound({ keyCode })); + } + + // Start the audio, if play button is clicked + function startAudio() { + interval = setInterval(() => { + + // Add hihat after 2nd round + if (++count === 32) { + createNotes(hihat, [1, 3, 5, 7, 9, 11, 13, 15]); + } + + // Add tink after 4th round + if (count === 32 * 2) { + createNotes(tink, [2, 4, 7, 12]); + } + if (count === 32 * 4) { + createNotes(tink, [3, 5, 8, 13]); + } + + playStep(currentStep - 1); + currentStep = (currentStep < totalSteps) ? currentStep + 1 : 1; + if (!playing) stopAudio(); + }, ~~(1500 / bpm)); + } + + // Stop the audio, if stop button is clicked + function stopAudio() { + clearInterval(interval); + currentStep = 1; + count = 0; + fullSteps = Array.from({ length: 16 }, () => []); + createFullNotes(); + keys.forEach(key => key.classList.remove('playing')); + } + + // Create setup for what instrument needs to be played at what step + function createNotes(instrument, steps) { + return Array.from(steps).map((step) => { + if (!Array.isArray(fullSteps[step - 1])) { + fullSteps[step - 1] = []; + } + fullSteps[step - 1].push(instrument) + }); + } + + // Create all the notes needed to play the initial audio + function createFullNotes() { + createNotes(kick, [1, 4, 7, 11]); + createNotes(snare, [5, 13]); + } + + // Initialize the initial audio notes + createFullNotes(); + + diff --git a/Challenges/Day 01 - JavaScript Drum Kit/index2.html b/Challenges/Day 01 - JavaScript Drum Kit/index2.html new file mode 100644 index 0000000..8083544 --- /dev/null +++ b/Challenges/Day 01 - JavaScript Drum Kit/index2.html @@ -0,0 +1,212 @@ + + + + + + + + + + JavaScript Drum Kit #2 | JavaScript30 | @palashmon + + + + + + +
+
+ A + clap +
+
+ S + hihat +
+
+ D + kick +
+
+ F + openhat +
+
+ G + boom +
+
+ H + ride +
+
+ J + snare +
+
+ K + tom +
+
+ L + tink +
+
+ + + + + + + + + + + + + + + + + + + diff --git a/Challenges/Day 01 - JavaScript Drum Kit/sounds/closedhat.wav b/Challenges/Day 01 - JavaScript Drum Kit/sounds/closedhat.wav new file mode 100644 index 0000000..2320db5 Binary files /dev/null and b/Challenges/Day 01 - JavaScript Drum Kit/sounds/closedhat.wav differ diff --git a/Challenges/Day 01 - JavaScript Drum Kit/sounds/tinkbell.wav b/Challenges/Day 01 - JavaScript Drum Kit/sounds/tinkbell.wav new file mode 100644 index 0000000..a59f9a5 Binary files /dev/null and b/Challenges/Day 01 - JavaScript Drum Kit/sounds/tinkbell.wav differ diff --git a/Challenges/Day 01 - JavaScript Drum Kit/style.css b/Challenges/Day 01 - JavaScript Drum Kit/style.css index 952497d..f25dd74 100644 --- a/Challenges/Day 01 - JavaScript Drum Kit/style.css +++ b/Challenges/Day 01 - JavaScript Drum Kit/style.css @@ -1,40 +1,88 @@ html { font-size: 10px; - background: url(http://i.imgur.com/b9r5sEL.jpg) bottom center; - background-size: cover; + background: #2980b9; /* fallback for old browsers */ + background: linear-gradient(300deg, deepskyblue, darkviolet, blue); + background-size: 180% 180%; + animation: gradient-animation 15s ease infinite; } -body,html { +* { + padding: 0; margin: 0; - padding: 0; - font-family: sans-serif; + box-sizing: border-box; +} +body, +html { + height: 100%; +} +body { + font-family: "Raleway", sans-serif; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.container { + display: grid; + grid-template-areas: + 'header' + 'content' + 'footer'; + grid-template-rows: 35% auto 40%; + grid-gap: 10px; + width: 100%; + height: 100%; +} +.container > * { + display: flex; + justify-content: center; + align-items: center; +} +header { + grid-area: header; +} +main { + grid-area: content; +} +footer { + grid-area: footer; +} +header h1 { + color: antiquewhite; + font-size: 6em; + text-transform: uppercase; + text-align: center; +} +header p { + color: antiquewhite; + font-size: 2em; + text-align: center; } .keys { - display:flex; - flex:1; - min-height:100vh; + display: flex; + flex: 1; align-items: center; justify-content: center; } .key { - border:4px solid black; - border-radius:5px; - margin:1rem; + border: 4px solid black; + border-radius: 5px; + margin: 1rem; font-size: 1.5rem; - padding:1rem .5rem; - transition:all .07s; - width:100px; + padding: 1rem 0.5rem; + transition: all 0.07s; + width: 100px; text-align: center; - color:white; - background:rgba(0,0,0,0.4); - text-shadow:0 0 5px black; + color: white; + background: rgba(0, 0, 0, 0.4); + text-shadow: 0 0 5px black; } .playing { - transform:scale(1.1); - border-color:#ffc600; + transform: scale(1.1); + border-color: #ffc600; box-shadow: 0 0 10px #ffc600; } @@ -47,5 +95,28 @@ kbd { font-size: 1.2rem; text-transform: uppercase; letter-spacing: 1px; - color:#ffc600; + color: #ffc600; +} + +input[type='button'] { + position: absolute; + margin-left: -50px; + left: 45%; + bottom: 20%; + border: 4px solid black; + border-radius: 5px; + margin: 1rem; + font-size: 2.5rem; + padding: 1rem 1.5rem; + transition: all 0.07s; + text-align: center; + color: white; + background: rgba(0, 0, 0, 0.4); + text-shadow: 0 0 5px black; +} + +@keyframes gradient-animation { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } } diff --git a/Challenges/Day 30 - Whack A Mole/clap.wav b/Challenges/Day 30 - Whack A Mole/clap.wav new file mode 100644 index 0000000..ef952e5 Binary files /dev/null and b/Challenges/Day 30 - Whack A Mole/clap.wav differ diff --git a/Challenges/Day 30 - Whack A Mole/index.html b/Challenges/Day 30 - Whack A Mole/index.html index 8d741d5..94104c7 100644 --- a/Challenges/Day 30 - Whack A Mole/index.html +++ b/Challenges/Day 30 - Whack A Mole/index.html @@ -1,14 +1,19 @@ + Whack A Mole! + -

Whack-a-mole! 0

+

Whack-a-mole!

+

Score: + 0 +

@@ -31,57 +36,61 @@

Whack-a-mole! 0

+ + + + diff --git a/Challenges/Day 30 - Whack A Mole/style.css b/Challenges/Day 30 - Whack A Mole/style.css index 8fec3f5..d3528a8 100644 --- a/Challenges/Day 30 - Whack A Mole/style.css +++ b/Challenges/Day 30 - Whack A Mole/style.css @@ -2,38 +2,48 @@ html { box-sizing: border-box; font-size: 10px; background: #ffc600; + background: -webkit-linear-gradient(to right, #f2c94c, #f2994a); + background: linear-gradient(to right, #f2c94c, #f2994a); } -*, *:before, *:after { +*, +*:before, +*:after { box-sizing: inherit; } body { padding: 0; - margin:0; + margin: 0; font-family: 'Amatic SC', cursive; + text-align: center; } h1 { text-align: center; font-size: 10rem; - line-height:1; + line-height: 1; margin-bottom: 0; } +h2 { + font-size: 3rem; + color: #391d04; + margin: 2rem; +} .score { - background:rgba(255,255,255,0.2); - padding:0 3rem; - line-height:1; - border-radius:1rem; + background: rgba(255, 255, 255, 0.2); + padding: 0 3rem; + line-height: 1; + border-radius: 1rem; } .game { - width:600px; - height:400px; - display:flex; - flex-wrap:wrap; - margin:0 auto; + width: 600px; + height: 400px; + display: flex; + flex-wrap: wrap; + margin: 0 auto; } .hole { @@ -45,25 +55,43 @@ h1 { .hole:after { display: block; background: url(dirt.svg) bottom center no-repeat; - background-size:contain; - content:''; + background-size: contain; + content: ''; width: 100%; - height:70px; + height: 70px; position: absolute; z-index: 2; - bottom:-30px; + bottom: -30px; } .mole { - background:url('mole.svg') bottom center no-repeat; - background-size:60%; + background: url('mole.svg') bottom center no-repeat; + background-size: 60%; position: absolute; top: 100%; width: 100%; height: 100%; - transition:all 0.4s; + transition: all 0.4s; + cursor: pointer; } .hole.up .mole { - top:0; + top: 0; +} + +button { + font-family: 'Amatic SC', cursive; + display: inline-block; + text-decoration: none; + border: 0; + border-radius: 1rem; + background: #391d04; + color: #fff; + font-size: 2.5rem; + padding: 1rem 1.5rem; + margin-bottom: 2rem; +} +button:hover { + opacity: 0.7; + cursor: pointer; } diff --git a/README.md b/README.md index 667667c..689bfa8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,16 @@ # JavaScript30 -> Course created by [Wes Bos](https://github.com/wesbos) +> Course created by [Wes Bos](https://github.com/wesbos). Join the challenge (for free!) here - [JavaScript30](https://javascript30.com/account) -> Join the challenge (for free!) here - [JavaScript30](https://javascript30.com/account) +![GitHub Stars](https://img.shields.io/github/stars/palashmon/JavaScript30) +![GitHub Forks](https://img.shields.io/github/forks/palashmon/JavaScript30?color=brightgreen) +![GitHub followers](https://img.shields.io/github/followers/palashmon?color=orange) +![GitHub language count](https://img.shields.io/github/languages/count/palashmon/JavaScript30?color=brightgreen) +![GitHub top language](https://img.shields.io/github/languages/top/palashmon/JavaScript30) + +

+ JavaScript30 +

Hi there! @@ -11,7 +19,7 @@ and commiting & logging what I have learnt on daily basis. Also, please have a look into the users I have helped so far regarding JavaScript30 course queries [here](/QUERIES.md). -If you have any JavaScript/JavaScript30 course realted queries, please create a new issue [here](https://github.com/palashmon/JavaScript30/issues/new). I will try to respond as soon as possible. I am always happy to help and learn new stuff from our JS community. +If you have any JavaScript/JavaScript30 course realted queries, please create a new issue [here](https://github.com/palashmon/JavaScript30/issues/new). I will try to respond as soon as possible. I am always happy to help and learn new stuff from our JS community. Thanks! @@ -20,36 +28,47 @@ Thanks! ## LOGS ### Day 1: 11 Dec 2016 -**Thoughts:** Learned about key event, transitionend event & ES6 template strings. + +**Thoughts:** Learned about key event, `transitionend` event & ES6 template strings. **Tool Found:** Nice tool for finding JavaScript event keycodes at [keycode.info](http://keycode.info/) +**Demo:** You can play/stop a auto drum routine by pressing spacebar [here](https://palashmon.github.io/JavaScript30/Challenges/Day%2001%20-%20JavaScript%20Drum%20Kit/) & [here](https://palashmon.github.io/JavaScript30/Challenges/Day%2001%20-%20JavaScript%20Drum%20Kit/index2.html) + ### Day 2: 13 Dec 2016 + **Thoughts:** Learned about Css transition & transform, ES6 const keyword and live UI update after few seconds. ### Day 3: 16 Dec 2016 + **Thoughts:** Learned about CSS variables & updating them using JavaScript ### Day 4: 22 Dec 2016 + **Thoughts:** Learned more about JavaScript array methods like filter, map, sort, reduce & others. Really liked ES6 Arrow functions. Shorter functions are most welcome. ![ES6 Arrow function](https://pbs.twimg.com/media/C0V10qtUcAAct4D.jpg) ### Day 5: 25 Dec 2016 -**Thoughts:** Learned few tips about flexbox. Planning to learn more about flexbox at [flexbox.io](http://flexbox.io/) soon. + +**Thoughts:** Learned few tips about flexbox. Planning to learn more about flexbox at [flexbox.io](http://flexbox.io/) soon. ### Day 6: 27 Dec 2016 -**Thoughts:** Learned about Fetch API, getting `.json()` from fetch response, ES6 spread operator. + +**Thoughts:** Learned about Fetch API, getting `.json()` from fetch response, ES6 spread operator. ### Day 7: 30 Dec 2016 -**Thoughts:** Learned about new array methods like some, every, find, findIndex. + +**Thoughts:** Learned about new array methods like some, every, find, findIndex. ![Day 7 of 30](https://pbs.twimg.com/media/C07gdtqUAAAtlyM.jpg) ### Day 8: 3 Jan 2017 + **Thoughts:** Had so much fun learning today. Did lots of coding & painting today. ![Canvas](https://pbs.twimg.com/media/C1QFNMYUsAA9cxC.jpg) ### Day 9: 5 Jan 2017 + **Thoughts:** Learned few useful Dev tools tricks. Debugging JavaScript code is so much fun, easy and colorful now. ![Canvas](https://pbs.twimg.com/media/C1fRlZCWQAAtuMx.jpg) @@ -57,28 +76,34 @@ Found one more useful trick called `console.trace()`. It helps to print a stack ![console.trace()](/Challenges/Images/console_trace.png) ### Day 10: 8 Jan 2017 + **Thoughts:** Learned a user-friendly feature used by popular email clients. **Tool Found:** It's so easy now to convert our ES5 code into readable ES6 using [lebab.io](https://lebab.io/try-it) ### Day 11: 9 Jan 2017 + **Thoughts:** Learned some nice tips on creating custom interface for HTML5 video player. Really liking the ES6 arrow functions from day 4 onwards. ![ES6 arrow functions](https://pbs.twimg.com/media/C1vYSZ7XUAEqZXS.jpg) -**Tool Found:** [ESLint v3.13.1](http://eslint.org/blog/2017/01/eslint-v3.13.1-released) has been released today. +**Tool Found:** [ESLint v3.13.1](http://eslint.org/blog/2017/01/eslint-v3.13.1-released) has been released today. ### Day 12: 10 Jan 2017 -**Thoughts:** Learned about key sequence detection & Konami code. Also, found that [BuzzFeed site](https://www.buzzfeed.com/)'s hidden easter egg is still working. To see it in action just press ':arrow_up: :arrow_up: :arrow_down: :arrow_down: :arrow_left: :arrow_right: :arrow_left: :arrow_right: B A'. + +**Thoughts:** Learned about key sequence detection & Konami code. Also, found that [BuzzFeed site](https://www.buzzfeed.com/)'s hidden easter egg is still working. To see it in action just press ':arrow_up: :arrow_up: :arrow_down: :arrow_down: :arrow_left: :arrow_right: :arrow_left: :arrow_right: B A'. ### Day 13: 11 Jan 2017 + **Thoughts:** Learned a bit more about window events & a very useful javascript debounce function. Today's project helped me to fix an issue related to resize events which was slowing down our site. The goal behind debounce implementation is to reduce overhead by preventing a function from being called several times in succession. ### Day 14: 12 Jan 2017 + **Thoughts:** Learned more about array & object reference vs actual copy. Found that primitive types are manipulated by value & reference types are manipulated by reference. Numbers and booleans are primitive types in JavaScript -- primitive because they consist of nothing more than a small, fixed number of bytes that are easily manipulated at the low (primitive) levels of the JavaScript interpreter. Objects, on the other hand, are reference types. Arrays and functions, which are specialized types of objects, are therefore also reference types. These data types can contain arbitrary numbers of properties or elements, so they cannot be manipulated as easily as fixed-size primitive values can. Since object and array values can become quite large, it doesn't make sense to manipulate these types by value, as this could involve the inefficient copying and comparing of large amounts of memory. ### Day 15: 13 Jan 2017 -**Thoughts:** Learned some useful stuff on local Storage & event delegation. + +**Thoughts:** Learned some useful stuff on local Storage & event delegation. Completed all of the project goals for today:- ![Day 15](https://pbs.twimg.com/media/C2EWpE7XgAAG3sp.jpg) @@ -87,66 +112,85 @@ Tested all new buttons. Data is also persisting on page reload:- ![Day 15 new taks](https://pbs.twimg.com/media/C2EYda5XUAAdUdh.jpg) ### Day 16: 14 Jan 2017 + **Thoughts:** Today learned about assigning to new variable names using ES6 Object destructuring and how we can update CSS rules like textShadow or anything using javascript. Just like canvas this was a fun challenge today. I tried some css effects like this:- ![Day 16 new taks](https://pbs.twimg.com/media/C2IFDhkWQAAv-Ck.jpg) ### Day 17: 15 Jan 2017 -**Thoughts:** Updated code to show modified band names on which sort actually happens and on right side the actual band names. After code modifications it looks like this:- + +**Thoughts:** Updated code to show modified band names on which sort actually happens and on right side the actual band names. After code modifications it looks like this:- ![Day 17 new taks](https://pbs.twimg.com/media/C2N0IDsWIAA9hLT.jpg) ### Day 18: 18 Jan 2017 + **Thoughts:** Learned more about `Array.prototype.reduce()` and its usability test case scenario. `reduce()` is quite simple & effective in specific scenarios like in the example below:- ![Day 18 new taks](https://pbs.twimg.com/media/C2eCp-xWgAAbhJz.jpg) -**Tools/Sites Found:** - - New, interactive Chrome Dev Tools tutorial: [How to analyze page load performance ⚡️🚀🔎](https://developers.google.com/web/tools/chrome-devtools/network-performance/) - - [2016 JavaScript Rising Stars](https://risingstars2016.js.org/) +**Tools/Sites Found:** + +- New, interactive Chrome Dev Tools tutorial: [How to analyze page load performance ⚡️🚀🔎](https://developers.google.com/web/tools/chrome-devtools/network-performance/) +- [2016 JavaScript Rising Stars](https://risingstars2016.js.org/) ### Day 19: 21 Jan 2017 + **Thoughts:** It was too much fun today. Learned a lot about canvas and pipelining real-time images. ### Day 20: 22 Jan 2017 + **Thoughts:** Learned about native [SpeechRecognition](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition) interface of the Web Speech API and how we can make use of it. Something like we do in google voice search. I think we can use it in various ways. Only limit is our imagination. Also liked the use npm [browser-sync](https://browsersync.io/) for time-saving synchronised browser testing. ### Day 21: 24 Jan 2017 -**Thoughts:** Worked on Device Orientation using Chrome sensors devtools. Also learned about Geolocation & Orientation Api. Unlike desktops, mobile devices commonly use GPS hardware to detect location. [Tweet Link Here 🐦](https://twitter.com/palashv2/status/823919145557299200) +**Thoughts:** Worked on Device Orientation using Chrome sensors devtools. Also learned about Geolocation & Orientation Api. Unlike desktops, mobile devices commonly use GPS hardware to detect location. [Tweet Link Here 🐦](https://twitter.com/palashv2/status/823919145557299200) ### Day 22: 29 Jan 2017 -**Thoughts:** Learned about `Element.getBoundingClientRect()` method and worked on some css effects [Tweet Link Here 🐦](https://twitter.com/palashv2/status/825757066669076480) + +**Thoughts:** Learned about `Element.getBoundingClientRect()` method and worked on some css effects [Tweet Link Here 🐦](https://twitter.com/palashv2/status/825757066669076480) ### Day 23: 5 Feb 2017 -**Thoughts:** "The Voiceinator 5000" challenge was great. Also, learned about SpeechSynthesis interface. + +**Thoughts:** "The Voiceinator 5000" challenge was great. Also, learned about SpeechSynthesis interface. ### Day 24: 11 Feb 2017 + **Thoughts:** Sticky Nav was really an interesting challenge. Learned about the requirement of padding top in nav element and other UI effects using css. ### Day 25: 11 Feb 2017 -**Thoughts:** Learned about `Event.stopPropagation()` & `EventTarget.addEventListener()` boolean options like capture, once & passive. More details about it here: - - https://developer.mozilla.org/en/docs/Web/API/Event/stopPropagation - - https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener + +**Thoughts:** Learned about `Event.stopPropagation()` & `EventTarget.addEventListener()` boolean options like capture, once & passive. More details about it here: + +- https://developer.mozilla.org/en/docs/Web/API/Event/stopPropagation +- https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener ### Day 26: 13 Feb 2017 + **Thoughts:** It was super-fun learning abt this really slick "follow along" nav found on Stripe's pricing page. [Tweet Link Here 🐦](https://twitter.com/palashv2/status/831161506301612036) ### Day 27: 14 Feb 2017 + **Thoughts:** Understood the basics behind the "Click and Drag to Scroll" challenge. element.offsetLeft play a great role in this logic. -**Tip:** Simple & time-saving tip +**Tip:** Simple & time-saving tip ![console image](https://pbs.twimg.com/media/C4oivhGVcAApV3E.jpg) ### Day 28: 15 Feb 2017 + **Thoughts:** Finished the fantastic video speed controller UI challenge today. These offset properties are pretty important for proper aligments. For block-level elements, `offsetTop`, `offsetLeft`, `offsetWidth`, and `offsetHeight` describe the border box of an element relative to the `offsetParent`. The `offsetParent` element is the nearest ancestor that has a position other than static. ### Day 29: 16 Feb 2017 -**Thoughts:** Finished the beeeeeeeeutiful countdown break clock challenge today. Learned about timestamps, set & clear intervals and `Date.now()`. The `Date.now()` method returns the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC. Because `now()` is a static method of Date, we can always use it as `Date.now()` instead of `new Date().now()`. + +**Thoughts:** Finished the beautiful countdown break clock challenge today. Learned about timestamps, set & clear intervals and `Date.now()`. The `Date.now()` method returns the number of milliseconds elapsed since `1 January 1970 00:00:00 UTC`. Because `now()` is a static method of Date, we can always use it as `Date.now()` instead of `new Date().now()`. ### Day 30: 20 Feb 2017 + **Thoughts:** Finally finished #JavaScript30 Day 30 Whack A Mole 🔨 challenge. It was fun learning experience. Highly recommend the entire course. +**Demo:** You can play the game [here](https://palashmon.github.io/JavaScript30/Challenges/Day%2030%20-%20Whack%20A%20Mole/) and keep the audio on for some fun. +## Note +If you like this repo and find it useful, please consider ★ starring it (on top right of the page). Thanks!