music kit thumbnail

Music Kit Using HTML, CSS and JavaScript

Introduction:

This project is a simple music kit implemented using HTML, CSS, and JavaScript. It allows users to play different drum sounds by clicking on buttons or pressing corresponding keys on the keyboard. The HTML file provides the structure of the user interface, the CSS file styles the elements, and the JavaScript file handles the logic for playing sounds and highlighting the pressed buttons.

This project represents a dynamic and interactive music kit designed to engage users in creating rhythmic compositions effortlessly. Leveraging the power of web technologies like HTML, CSS, and JavaScript, it provides a seamless platform for users to explore their musical creativity.

Overall, the project serves as a testament to the boundless potential of web technologies in fostering creativity and innovation. Whether used as a standalone tool for musical experimentation or integrated into larger multimedia projects, the music kit represents a harmonious blend of artistry and technology, inviting users to embark on a journey of sonic exploration and self-expression

At its core, the project offers a visually intuitive interface comprising drum buttons, each mapped to a distinct percussive sound. Users can trigger these sounds either by clicking on the graphical buttons or by pressing corresponding keys on their keyboards, fostering a fluid and immersive user experience.

Through a combination of HTML for structure, CSS for styling, and JavaScript for interactivity, the project encapsulates the essence of web development, showcasing the synergy between design and functionality. This synergy not only facilitates seamless interaction but also ensures that users of all skill levels can effortlessly navigate and utilize the music kit to express themselves creatively.

By encapsulating audio files within a JavaScript module and dynamically associating them with button clicks or key presses, the project demonstrates the versatility and extensibility of modern web development techniques. This modular approach not only enhances maintainability but also allows for easy scalability, enabling the addition of new sounds or features with minimal effort.

Overall, the project serves as a testament to the boundless potential of web technologies in fostering creativity and innovation. Whether used as a standalone tool for musical experimentation or integrated into larger multimedia projects, the music kit represents a harmonious blend of artistry and technology, inviting users to embark on a journey of sonic exploration and self-expression.

Explanation :

HTML (index.html):

  • The HTML file defines the structure of the web page.
  • It includes references to the JavaScript file (musickit.js) and the CSS file (styles.css).
  • Inside the <body> tag, there is a <div> with the class “set”, which contains buttons representing different drum sounds.

CSS (styles.css):

  • Defines the styles for the drum buttons and their hover effects.
  • Each drum button has a specific background image and styling for its appearance.
  • It also includes media queries for adjusting the layout on different screen sizes.

JavaScript (musickit.js):

  • Imports audio files for each drum sound.
  • Defines a map (sounds) that maps drum button characters to their corresponding audio files.
  • Adds event listeners to each drum button to play the associated sound when clicked.
  • Listens for keypress events and plays the corresponding sound.
  • Provides functions (makeSound and highlightPressedButton) to play the sound and highlight the pressed button, respectively.

JavaScript Logic:

  1. Imports: Import audio files for each drum sound.
  2. sounds Map: Maps drum button characters to their corresponding audio files.
  3. Event Listeners:
    • Adds click event listeners to each drum button to play the associated sound and highlight the pressed button.
    • Listens for keypress events to play the corresponding sound and highlight the pressed button.
  4. makeSound Function: Plays the sound associated with the pressed button.
  5. highlightPressedButton Function: Highlights the pressed button by adding the “pressed” class and removes the class from the previously pressed button.

At the heart of the project lies the JavaScript file, which orchestrates the interactive behavior of the music kit. Leveraging modern ES6 features such as modules and arrow functions, it encapsulates functionality in a modular and maintainable manner. Through the use of the import statement, audio files for each drum sound are seamlessly integrated into the project, facilitating code organization and reuse. A Map data structure is employed to establish a mapping between drum button characters and their corresponding audio files, enabling efficient retrieval and playback.

Event Handling:

The JavaScript file implements event listeners to capture user interactions and trigger appropriate responses. Click event listeners are attached to each drum button, allowing users to play sounds by clicking on the graphical interface. Similarly, a keypress event listener listens for keyboard input, enabling users to trigger sounds by pressing corresponding keys. This dual input mechanism enhances accessibility and user engagement, catering to diverse preferences and input modalities.

Functions and Modularity:

To promote code readability and maintainability, the JavaScript file defines reusable functions that encapsulate distinct pieces of functionality. The makeSound function encapsulates the logic for playing audio files based on user input, facilitating code reuse and abstraction. Similarly, the highlightPressedButton function manages the visual highlighting of pressed buttons, enhancing user feedback and interaction. By adopting a modular approach, the project exhibits best practices in software design, fostering extensibility and scalability.

In conclusion, the music kit project represents a harmonious fusion of design, functionality, and user experience, showcasing the transformative power of web technologies in fostering creativity and innovation. Through meticulous attention to detail, modular design principles, and a user-centric approach, the project exemplifies best practices in web development, serving as a testament to the limitless possibilities of digital expression and artistic exploration. Whether used as a standalone tool for musical experimentation or integrated into larger multimedia endeavors, the music kit embodies the ethos of web development as a catalyst for creativity and self-expression.

Purpose of Functions:

  • makeSound: Plays the audio file associated with the pressed drum button or key.
  • highlightPressedButton: Highlights the currently pressed button visually by adding a CSS class and removes the highlight from the previously pressed button.

SOURCE CODE :

HTML (index.html)

				
					<!DOCTYPE html>
<html lang="en" dir="ltr">

<head> <script src="musickit.js" type="module"></script> <link rel="stylesheet" href="styles.css" />
  <title>Music Kit</title>
</head>

<body>
  <div class="set">
    <button class="w drum">w</button>
    <button class="a drum">a</button>
    <button class="s drum">s</button>
    <button class="d drum">d</button>
    <button class="j drum">j</button>
    <button class="k drum">k</button>
    <button class="l drum">l</button>
  </div> <script data-no-optimize="1">!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).LazyLoad=e()}(this,function(){"use strict";function e(){return(e=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n,a=arguments[e];for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(t[n]=a[n])}return t}).apply(this,arguments)}function i(t){return e({},it,t)}function o(t,e){var n,a="LazyLoad::Initialized",i=new t(e);try{n=new CustomEvent(a,{detail:{instance:i}})}catch(t){(n=document.createEvent("CustomEvent")).initCustomEvent(a,!1,!1,{instance:i})}window.dispatchEvent(n)}function l(t,e){return t.getAttribute(gt+e)}function c(t){return l(t,bt)}function s(t,e){return function(t,e,n){e=gt+e;null!==n?t.setAttribute(e,n):t.removeAttribute(e)}(t,bt,e)}function r(t){return s(t,null),0}function u(t){return null===c(t)}function d(t){return c(t)===vt}function f(t,e,n,a){t&&(void 0===a?void 0===n?t(e):t(e,n):t(e,n,a))}function _(t,e){nt?t.classList.add(e):t.className+=(t.className?" ":"")+e}function v(t,e){nt?t.classList.remove(e):t.className=t.className.replace(new RegExp("(^|\\s+)"+e+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")}function g(t){return t.llTempImage}function b(t,e){!e||(e=e._observer)&&e.unobserve(t)}function p(t,e){t&&(t.loadingCount+=e)}function h(t,e){t&&(t.toLoadCount=e)}function n(t){for(var e,n=[],a=0;e=t.children[a];a+=1)"SOURCE"===e.tagName&&n.push(e);return n}function m(t,e){(t=t.parentNode)&&"PICTURE"===t.tagName&&n(t).forEach(e)}function a(t,e){n(t).forEach(e)}function E(t){return!!t[st]}function I(t){return t[st]}function y(t){return delete t[st]}function A(e,t){var n;E(e)||(n={},t.forEach(function(t){n[t]=e.getAttribute(t)}),e[st]=n)}function k(a,t){var i;E(a)&&(i=I(a),t.forEach(function(t){var e,n;e=a,(t=i[n=t])?e.setAttribute(n,t):e.removeAttribute(n)}))}function L(t,e,n){_(t,e.class_loading),s(t,ut),n&&(p(n,1),f(e.callback_loading,t,n))}function w(t,e,n){n&&t.setAttribute(e,n)}function x(t,e){w(t,ct,l(t,e.data_sizes)),w(t,rt,l(t,e.data_srcset)),w(t,ot,l(t,e.data_src))}function O(t,e,n){var a=l(t,e.data_bg_multi),i=l(t,e.data_bg_multi_hidpi);(a=at&&i?i:a)&&(t.style.backgroundImage=a,n=n,_(t=t,(e=e).class_applied),s(t,ft),n&&(e.unobserve_completed&&b(t,e),f(e.callback_applied,t,n)))}function N(t,e){!e||0<e.loadingCount||0<e.toLoadCount||f(t.callback_finish,e)}function C(t,e,n){t.addEventListener(e,n),t.llEvLisnrs[e]=n}function M(t){return!!t.llEvLisnrs}function z(t){if(M(t)){var e,n,a=t.llEvLisnrs;for(e in a){var i=a[e];n=e,i=i,t.removeEventListener(n,i)}delete t.llEvLisnrs}}function R(t,e,n){var a;delete t.llTempImage,p(n,-1),(a=n)&&--a.toLoadCount,v(t,e.class_loading),e.unobserve_completed&&b(t,n)}function T(o,r,c){var l=g(o)||o;M(l)||function(t,e,n){M(t)||(t.llEvLisnrs={});var a="VIDEO"===t.tagName?"loadeddata":"load";C(t,a,e),C(t,"error",n)}(l,function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_loaded),s(e,dt),f(n.callback_loaded,e,a),i||N(n,a),z(l)},function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_error),s(e,_t),f(n.callback_error,e,a),i||N(n,a),z(l)})}function G(t,e,n){var a,i,o,r,c;t.llTempImage=document.createElement("IMG"),T(t,e,n),E(c=t)||(c[st]={backgroundImage:c.style.backgroundImage}),o=n,r=l(a=t,(i=e).data_bg),c=l(a,i.data_bg_hidpi),(r=at&&c?c:r)&&(a.style.backgroundImage='url("'.concat(r,'")'),g(a).setAttribute(ot,r),L(a,i,o)),O(t,e,n)}function D(t,e,n){var a;T(t,e,n),a=e,e=n,(t=It[(n=t).tagName])&&(t(n,a),L(n,a,e))}function V(t,e,n){var a;a=t,(-1<yt.indexOf(a.tagName)?D:G)(t,e,n)}function F(t,e,n){var a;t.setAttribute("loading","lazy"),T(t,e,n),a=e,(e=It[(n=t).tagName])&&e(n,a),s(t,vt)}function j(t){t.removeAttribute(ot),t.removeAttribute(rt),t.removeAttribute(ct)}function P(t){m(t,function(t){k(t,Et)}),k(t,Et)}function S(t){var e;(e=At[t.tagName])?e(t):E(e=t)&&(t=I(e),e.style.backgroundImage=t.backgroundImage)}function U(t,e){var n;S(t),n=e,u(e=t)||d(e)||(v(e,n.class_entered),v(e,n.class_exited),v(e,n.class_applied),v(e,n.class_loading),v(e,n.class_loaded),v(e,n.class_error)),r(t),y(t)}function $(t,e,n,a){var i;n.cancel_on_exit&&(c(t)!==ut||"IMG"===t.tagName&&(z(t),m(i=t,function(t){j(t)}),j(i),P(t),v(t,n.class_loading),p(a,-1),r(t),f(n.callback_cancel,t,e,a)))}function q(t,e,n,a){var i,o,r=(o=t,0<=pt.indexOf(c(o)));s(t,"entered"),_(t,n.class_entered),v(t,n.class_exited),i=t,o=a,n.unobserve_entered&&b(i,o),f(n.callback_enter,t,e,a),r||V(t,n,a)}function H(t){return t.use_native&&"loading"in HTMLImageElement.prototype}function B(t,i,o){t.forEach(function(t){return(a=t).isIntersecting||0<a.intersectionRatio?q(t.target,t,i,o):(e=t.target,n=t,a=i,t=o,void(u(e)||(_(e,a.class_exited),$(e,n,a,t),f(a.callback_exit,e,n,t))));var e,n,a})}function J(e,n){var t;et&&!H(e)&&(n._observer=new IntersectionObserver(function(t){B(t,e,n)},{root:(t=e).container===document?null:t.container,rootMargin:t.thresholds||t.threshold+"px"}))}function K(t){return Array.prototype.slice.call(t)}function Q(t){return t.container.querySelectorAll(t.elements_selector)}function W(t){return c(t)===_t}function X(t,e){return e=t||Q(e),K(e).filter(u)}function Y(e,t){var n;(n=Q(e),K(n).filter(W)).forEach(function(t){v(t,e.class_error),r(t)}),t.update()}function t(t,e){var n,a,t=i(t);this._settings=t,this.loadingCount=0,J(t,this),n=t,a=this,Z&&window.addEventListener("online",function(){Y(n,a)}),this.update(e)}var Z="undefined"!=typeof window,tt=Z&&!("onscroll"in window)||"undefined"!=typeof navigator&&/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),et=Z&&"IntersectionObserver"in window,nt=Z&&"classList"in document.createElement("p"),at=Z&&1<window.devicePixelRatio,it={elements_selector:".lazy",container:tt||Z?document:null,threshold:300,thresholds:null,data_src:"src",data_srcset:"srcset",data_sizes:"sizes",data_bg:"bg",data_bg_hidpi:"bg-hidpi",data_bg_multi:"bg-multi",data_bg_multi_hidpi:"bg-multi-hidpi",data_poster:"poster",class_applied:"applied",class_loading:"litespeed-loading",class_loaded:"litespeed-loaded",class_error:"error",class_entered:"entered",class_exited:"exited",unobserve_completed:!0,unobserve_entered:!1,cancel_on_exit:!0,callback_enter:null,callback_exit:null,callback_applied:null,callback_loading:null,callback_loaded:null,callback_error:null,callback_finish:null,callback_cancel:null,use_native:!1},ot="src",rt="srcset",ct="sizes",lt="poster",st="llOriginalAttrs",ut="loading",dt="loaded",ft="applied",_t="error",vt="native",gt="data-",bt="ll-status",pt=[ut,dt,ft,_t],ht=[ot],mt=[ot,lt],Et=[ot,rt,ct],It={IMG:function(t,e){m(t,function(t){A(t,Et),x(t,e)}),A(t,Et),x(t,e)},IFRAME:function(t,e){A(t,ht),w(t,ot,l(t,e.data_src))},VIDEO:function(t,e){a(t,function(t){A(t,ht),w(t,ot,l(t,e.data_src))}),A(t,mt),w(t,lt,l(t,e.data_poster)),w(t,ot,l(t,e.data_src)),t.load()}},yt=["IMG","IFRAME","VIDEO"],At={IMG:P,IFRAME:function(t){k(t,ht)},VIDEO:function(t){a(t,function(t){k(t,ht)}),k(t,mt),t.load()}},kt=["IMG","IFRAME","VIDEO"];return t.prototype={update:function(t){var e,n,a,i=this._settings,o=X(t,i);{if(h(this,o.length),!tt&&et)return H(i)?(e=i,n=this,o.forEach(function(t){-1!==kt.indexOf(t.tagName)&&F(t,e,n)}),void h(n,0)):(t=this._observer,i=o,t.disconnect(),a=t,void i.forEach(function(t){a.observe(t)}));this.loadAll(o)}},destroy:function(){this._observer&&this._observer.disconnect(),Q(this._settings).forEach(function(t){y(t)}),delete this._observer,delete this._settings,delete this.loadingCount,delete this.toLoadCount},loadAll:function(t){var e=this,n=this._settings;X(t,n).forEach(function(t){b(t,e),V(t,n,e)})},restoreAll:function(){var e=this._settings;Q(e).forEach(function(t){U(t,e)})}},t.load=function(t,e){e=i(e);V(t,e)},t.resetStatus=function(t){r(t)},Z&&function(t,e){if(e)if(e.length)for(var n,a=0;n=e[a];a+=1)o(t,n);else o(t,e)}(t,window.lazyLoadOptions),t});!function(e,t){"use strict";function a(){t.body.classList.add("litespeed_lazyloaded")}function n(){console.log("[LiteSpeed] Start Lazy Load Images"),d=new LazyLoad({elements_selector:"[data-lazyloaded]",callback_finish:a}),o=function(){d.update()},e.MutationObserver&&new MutationObserver(o).observe(t.documentElement,{childList:!0,subtree:!0,attributes:!0})}var d,o;e.addEventListener?e.addEventListener("load",n,!1):e.attachEvent("onload",n)}(window,document);</script><script data-no-optimize="1">var litespeed_vary=document.cookie.replace(/(?:(?:^|.*;\s*)_lscache_vary\s*\=\s*([^;]*).*$)|^.*$/,"");litespeed_vary||fetch("/wp-content/plugins/litespeed-cache/guest.vary.php",{method:"POST",cache:"no-cache",redirect:"follow"}).then(e=>e.json()).then(e=>{console.log(e),e.hasOwnProperty("reload")&&"yes"==e.reload&&(sessionStorage.setItem("litespeed_docref",document.referrer),window.location.reload(!0))});</script><script data-optimized="1" type="litespeed/javascript" data-src="https://foolishdeveloper.com/wp-content/litespeed/js/f21cbb88936c42dc19773a8407b9c20a.js?ver=519e0"></script><script>const litespeed_ui_events=["mouseover","click","keydown","wheel","touchmove","touchstart"];var urlCreator=window.URL||window.webkitURL;function litespeed_load_delayed_js_force(){console.log("[LiteSpeed] Start Load JS Delayed"),litespeed_ui_events.forEach(e=>{window.removeEventListener(e,litespeed_load_delayed_js_force,{passive:!0})}),document.querySelectorAll("iframe[data-litespeed-src]").forEach(e=>{e.setAttribute("src",e.getAttribute("data-litespeed-src"))}),"loading"==document.readyState?window.addEventListener("DOMContentLoaded",litespeed_load_delayed_js):litespeed_load_delayed_js()}litespeed_ui_events.forEach(e=>{window.addEventListener(e,litespeed_load_delayed_js_force,{passive:!0})});async function litespeed_load_delayed_js(){let t=[];for(var d in document.querySelectorAll('script[type="litespeed/javascript"]').forEach(e=>{t.push(e)}),t)await new Promise(e=>litespeed_load_one(t[d],e));document.dispatchEvent(new Event("DOMContentLiteSpeedLoaded")),window.dispatchEvent(new Event("DOMContentLiteSpeedLoaded"))}function litespeed_load_one(t,e){console.log("[LiteSpeed] Load ",t);var d=document.createElement("script");d.addEventListener("load",e),d.addEventListener("error",e),t.getAttributeNames().forEach(e=>{"type"!=e&&d.setAttribute("data-src"==e?"src":e,t.getAttribute(e))});let a=!(d.type="text/javascript");!d.src&&t.textContent&&(d.src=litespeed_inline2src(t.textContent),a=!0),t.after(d),t.remove(),a&&e()}function litespeed_inline2src(t){try{var d=urlCreator.createObjectURL(new Blob([t.replace(/^(?:<!--)?(.*?)(?:-->)?$/gm,"$1")],{type:"text/javascript"}))}catch(e){d="data:text/javascript;base64,"+btoa(t.replace(/^(?:<!--)?(.*?)(?:-->)?$/gm,"$1"))}return d}</script></body>

</html>
				
			

CSS (style.css)

				
					
.set {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 2rem;
  flex-wrap: wrap;
}

.drum {
  border: 2px solid #333;
  background-color: #fff;
  font-size: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background-color 0.2s, transform 0.2s;
  border: 10px solid #404b69;
  font-size: 5rem;
  line-height: 2;
  font-weight: 900;
  color: #da0463;
  text-shadow: 3px 0 #dbedf3;
  width: 115px;
  height: 115px;
  border-radius: 15px;
  margin: 10px;
}

/* Add hover effect to drum buttons */
.drum:hover {
  background-color: #333;
  color: blue;
  transform: scale(1.1);
}

.w {
  background-image: url('images/tom1.png');
}

.a {
  background-image: url('images/tom2.png');
}

.s {
  background-image: url('images/tom3.png');
}

.d {
  background-image: url('images/tom4.png');
}

.j {
  background-image: url('images/snare.png');
}

.k {
  background-image: url('images/crash.png');
}

.l {
  background-image: url('images/kick.png');
}

.pressed {
  box-shadow: 0 3px 4px 0 #dbedf3;
  opacity: 0.5;
}

.red {
  color: red;
}

@media (width >=768px) {
  .set {
    margin: 10% auto;
  }

  .drum {
    width: 150px;
    height: 150px;
  }
}
				
			

JavaScript ( musickit.js)

				
					import tom1 from './sounds/tom-1.mp3';
import tom2 from './sounds/tom-2.mp3';
import tom3 from './sounds/tom-3.mp3';
import tom4 from './sounds/tom-4.mp3';
import snare from './sounds/snare.mp3';
import crash from './sounds/crash.mp3';
import kick from './sounds/kick-bass.mp3';

const sounds = new Map([
  ['w', tom1],
  ['a', tom2],
  ['s', tom3],
  ['d', tom4],
  ['j', snare],
  ['k', crash],
  ['l', kick],
]);

const numberOfDrumButtons = document.querySelectorAll('.drum').length;

for (let i = 0; i < numberOfDrumButtons; i++) {
  document.querySelectorAll('.drum')[i].addEventListener('click', function () {
    const buttonInnerHTML = this.textContent;
    makeSound(buttonInnerHTML);
    highlightPressedButton(buttonInnerHTML);
  });
}

document.addEventListener('keypress', function (event) {
  makeSound(event.key);
  highlightPressedButton(event.key);
});

function makeSound(key) {
  const audio = new Audio(sounds.get(key));
  audio.play();
}

function highlightPressedButton(currentKey) {
  const pressedButton = document.querySelector('.pressed');
  if (pressedButton) {
    pressedButton.classList.remove('pressed');
  }

  const activeButton = document.querySelector('.' + currentKey);
  activeButton?.classList.add('pressed');
}

				
			

Download the images and sounds used in this project :

OUTPUT :

output