diff --git a/examples/Drum_kit/README.md b/examples/Drum_kit/README.md
new file mode 100644
index 00000000..a071b824
--- /dev/null
+++ b/examples/Drum_kit/README.md
@@ -0,0 +1,34 @@
+# Drum Kit — WebAudio demo
+
+This is a small interactive drum kit demo using plain HTML, CSS and JavaScript.
+
+Features
+- Play drum sounds by clicking pads or pressing mapped keys:
+ - W - Crash
+ - A - Kick
+ - S - Snare
+ - D - Mid Tom
+ - J - HiHat Closed
+ - K - HiHat Open
+ - L - Clap
+ - ; - Low Tom
+- Visual button animations on play.
+- Record a short sequence and play it back.
+- Adjustable master volume control.
+- Save and load your drum patterns as JSON files.
+- Full keyboard accessibility with ARIA labels and focus indicators.Files
+- `index.html` — markup and UI
+- `styles.css` — styles and small animations
+- `script.js` — Web Audio synths, event handling, recording/playback logic
+
+Usage
+1. Open `index.html` in a browser (Chrome, Firefox, Edge). For best results, open it via a web server (e.g. `python -m http.server`) because some browsers restrict AudioContext on file://.
+2. Click a pad or press W/A/S/D to play sounds.
+3. Press "Record", play some beats, then "Stop" and "Play" to hear them.
+
+Notes
+- Sounds are synthesized using the Web Audio API (no external audio files required).
+- The demo uses a lazy AudioContext creation strategy — the context starts when you interact with the page.
+- Recording stores event times (ms) relative to the moment recording started and schedules playback with the AudioContext time base.
+
+Enjoy!
diff --git a/examples/Drum_kit/index.html b/examples/Drum_kit/index.html
new file mode 100644
index 00000000..c6df1eb4
--- /dev/null
+++ b/examples/Drum_kit/index.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+ Drum Kit
+
+
+
+
+ Drum Kits 🥁
+
+
+ CrashW
+ KickA
+ SnareS
+ TomD
+ HiHat CJ
+ HiHat OK
+ ClapL
+ Low Tom;
+
+
+
+ 🔊 Volume
+
+ 90%
+
+
+
+
● Record
+
■ Stop
+
▶ Play
+
✕ Clear
+
⬇ Save
+
⬆ Load
+
+
Idle
+
+
+ Tip: Click a pad or press the keys on your keyboard to play. Try recording a short beat!
+
+
+
+
+
diff --git a/examples/Drum_kit/script.js b/examples/Drum_kit/script.js
new file mode 100644
index 00000000..3e3dec19
--- /dev/null
+++ b/examples/Drum_kit/script.js
@@ -0,0 +1,377 @@
+// Drum kit using Web Audio API
+// - Click or press W A S D to play sounds
+// - Record/Stop/Play/Clear sequence with timing
+
+// Simple mapping: key -> instrument
+const MAPPING = {
+ w: 'crash',
+ a: 'kick',
+ s: 'snare',
+ d: 'tom',
+ j: 'hihatClosed',
+ k: 'hihatOpen',
+ l: 'clap',
+ ';': 'lowTom'
+};
+
+// Create AudioContext lazily (user gesture required in many browsers)
+let audioCtx = null;
+let masterGain = null;
+function ensureAudio(){
+ if(!audioCtx){
+ audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+ masterGain = audioCtx.createGain();
+ masterGain.gain.value = 0.9; // master volume
+ masterGain.connect(audioCtx.destination);
+ }
+ // Some browsers (Chrome mobile) start suspended until explicit resume after a gesture
+ if(audioCtx.state === 'suspended'){
+ audioCtx.resume();
+ }
+ return audioCtx;
+}
+
+// Basic drum synthesizers using WebAudio primitives
+function playCrash(time){
+ const ctx = ensureAudio();
+ const o = ctx.createBufferSource();
+ // generate short noise buffer
+ const buffer = ctx.createBuffer(1, ctx.sampleRate * 1.0, ctx.sampleRate);
+ const data = buffer.getChannelData(0);
+ for(let i=0;i {
+ const bp = ctx.createBiquadFilter();
+ bp.type='bandpass';
+ bp.frequency.value = f;
+ node.connect(bp);
+ node = bp;
+ });
+ const g = ctx.createGain();
+ const decay = closed ? 0.09 : 0.4;
+ g.gain.setValueAtTime(closed?0.8:0.7, t);
+ g.gain.exponentialRampToValueAtTime(0.0001, t + decay);
+ node.connect(g).connect(masterGain || ctx.destination);
+ src.start(t);
+ src.stop(t + decay + 0.02);
+}
+
+function playClap(time){
+ const ctx = ensureAudio();
+ const t = (time ?? ctx.currentTime);
+ // Clap: 3 quick noise bursts with exponential decay
+ const bursts = [0, 0.02, 0.04];
+ bursts.forEach(offset => {
+ const noise = ctx.createBufferSource();
+ const buffer = ctx.createBuffer(1, ctx.sampleRate * 0.25, ctx.sampleRate);
+ const data = buffer.getChannelData(0);
+ for(let i=0;i{
+ const val = e.target.value;
+ if(masterGain){
+ masterGain.gain.value = val / 100;
+ }
+ volumeValue.textContent = val + '%';
+});
+
+function animateButton(key){
+ const btn = buttons.find(b => b.dataset.key === key);
+ if(!btn) return;
+ btn.classList.add('playing','pulse');
+ setTimeout(()=> btn.classList.remove('pulse'), 360);
+ setTimeout(()=> btn.classList.remove('playing'), 140);
+}
+
+// Recording
+let recording = [];
+let isRecording = false;
+let recordStart = 0;
+
+const recordBtn = document.getElementById('record');
+const stopBtn = document.getElementById('stop');
+const playBtn = document.getElementById('play');
+const clearBtn = document.getElementById('clear');
+
+recordBtn.addEventListener('click', ()=>{
+ ensureAudio();
+ recording = [];
+ isRecording = true;
+ recordStart = performance.now();
+ statusEl.textContent = 'Recording...';
+ statusEl.classList.add('recording');
+ recordBtn.disabled = true;
+ stopBtn.disabled = false;
+ playBtn.disabled = true;
+ clearBtn.disabled = true;
+ downloadBtn.disabled = true;
+});
+
+stopBtn.addEventListener('click', ()=>{
+ isRecording = false;
+ statusEl.textContent = 'Idle';
+ statusEl.classList.remove('recording');
+ recordBtn.disabled = false;
+ stopBtn.disabled = true;
+ playBtn.disabled = recording.length === 0;
+ clearBtn.disabled = recording.length === 0;
+ downloadBtn.disabled = recording.length === 0;
+});
+
+playBtn.addEventListener('click', async ()=>{
+ if(recording.length === 0) return;
+ statusEl.textContent = 'Playing...';
+ recordBtn.disabled = true; playBtn.disabled = true; stopBtn.disabled = true; clearBtn.disabled = true;
+ const ctx = ensureAudio();
+ const start = ctx.currentTime + 0.1;
+ for(const ev of recording){
+ playInstrument(ev.inst, start + ev.time/1000);
+ // schedule UI animation (Best-effort using setTimeout)
+ setTimeout(()=> animateButton(ev.key), (start - ctx.currentTime) * 1000 + ev.time);
+ }
+ // re-enable after last event
+ const duration = Math.max(...recording.map(r=>r.time)) + 800;
+ setTimeout(()=>{
+ statusEl.textContent = 'Idle';
+ recordBtn.disabled = false;
+ playBtn.disabled = false;
+ clearBtn.disabled = false;
+ }, duration);
+});
+
+clearBtn.addEventListener('click', ()=>{
+ recording = [];
+ playBtn.disabled = true;
+ clearBtn.disabled = true;
+ downloadBtn.disabled = true;
+ statusEl.textContent = 'Cleared';
+ setTimeout(()=> statusEl.textContent = 'Idle', 800);
+});
+
+const downloadBtn = document.getElementById('download');
+const uploadBtn = document.getElementById('upload');
+const fileInput = document.getElementById('file-input');
+
+// Download pattern as JSON
+downloadBtn.addEventListener('click', ()=>{
+ if(recording.length === 0) return;
+ const data = JSON.stringify(recording, null, 2);
+ const blob = new Blob([data], {type: 'application/json'});
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = `drum-pattern-${Date.now()}.json`;
+ a.click();
+ URL.revokeObjectURL(url);
+ statusEl.textContent = 'Pattern saved!';
+ setTimeout(()=> statusEl.textContent = 'Idle', 1500);
+});
+
+// Upload pattern from JSON
+uploadBtn.addEventListener('click', ()=>{
+ fileInput.click();
+});
+
+fileInput.addEventListener('change', (e)=>{
+ const file = e.target.files[0];
+ if(!file) return;
+ const reader = new FileReader();
+ reader.onload = (evt)=>{
+ try{
+ const loaded = JSON.parse(evt.target.result);
+ if(Array.isArray(loaded) && loaded.length > 0){
+ recording = loaded;
+ playBtn.disabled = false;
+ clearBtn.disabled = false;
+ downloadBtn.disabled = false;
+ statusEl.textContent = 'Pattern loaded!';
+ setTimeout(()=> statusEl.textContent = 'Idle', 1500);
+ }else{
+ statusEl.textContent = 'Invalid pattern';
+ setTimeout(()=> statusEl.textContent = 'Idle', 1500);
+ }
+ }catch(err){
+ statusEl.textContent = 'Error loading file';
+ setTimeout(()=> statusEl.textContent = 'Idle', 1500);
+ }
+ };
+ reader.readAsText(file);
+ e.target.value = ''; // reset input
+});
+
+// Play one event: handles scheduling and recording
+function triggerKey(key){
+ const inst = MAPPING[key];
+ if(!inst) return;
+ const ctx = ensureAudio();
+ playInstrument(inst, ctx.currentTime + 0);
+ animateButton(key);
+ if(isRecording){
+ recording.push({key, inst, time: performance.now() - recordStart});
+ playBtn.disabled = false; clearBtn.disabled = false;
+ }
+}
+
+// Mouse click handlers
+buttons.forEach(btn => btn.addEventListener('click', e => {
+ // ensure audio is started on first interaction
+ ensureAudio();
+ const key = btn.dataset.key;
+ triggerKey(key);
+}));
+
+// Keyboard handlers
+window.addEventListener('keydown', (e)=>{
+ // Prevent repeated triggering when key is held down
+ if(e.repeat) return;
+ const k = e.key.toLowerCase();
+ if(MAPPING[k]){
+ ensureAudio();
+ triggerKey(k);
+ }
+});
+
+// Accessibility: expose mapping in console
+console.log('Drum kit ready. Keys:', MAPPING);
diff --git a/examples/Drum_kit/styles.css b/examples/Drum_kit/styles.css
new file mode 100644
index 00000000..a4fdbcad
--- /dev/null
+++ b/examples/Drum_kit/styles.css
@@ -0,0 +1,172 @@
+:root{
+ --bg: #ffd6e0;
+ --card: #fff;
+ --accent: #ff6f91;
+ --shadow: rgba(0,0,0,0.12);
+}
+*{box-sizing:border-box}
+body{
+ margin:0;
+ font-family: Inter, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial;
+ background: linear-gradient(180deg, var(--bg), #ffeef6);
+ color:#333;
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ min-height:100vh;
+}
+.container{
+ width:min(900px, 94%);
+ text-align:center;
+}
+.title{
+ font-size:2.4rem;
+ letter-spacing:1px;
+ margin:0 0 18px 0;
+ color: #e46363;
+ text-shadow: 0 4px 10px rgba(0,0,0,0.12);
+}
+.kits{
+ display:flex;
+ gap:18px;
+ justify-content:center;
+ flex-wrap:wrap;
+ margin-bottom:18px;
+}
+.drum{
+ background:var(--card);
+ border-radius:12px;
+ width:140px;
+ height:92px;
+ border:0;
+ box-shadow:0 8px 20px var(--shadow);
+ cursor:pointer;
+ font-size:1.1rem;
+ padding:12px;
+ position:relative;
+ transition:transform .08s ease, box-shadow .12s ease;
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ flex-direction:column;
+}
+.drum:active,
+.drum.playing{
+ transform:translateY(6px) scale(.98);
+ box-shadow:0 4px 12px rgba(0,0,0,0.10);
+}
+.drum:focus-visible{
+ outline: 3px solid var(--accent);
+ outline-offset: 2px;
+}
+.drum .key{
+ display:block;
+ font-size:.85rem;
+ margin-top:6px;
+ color:#666;
+}
+.controls{
+ display:flex;
+ gap:8px;
+ justify-content:center;
+ align-items:center;
+ margin-top:12px;
+ flex-wrap:wrap;
+}
+.controls button{
+ background:transparent;
+ border:2px solid rgba(255,111,145,0.18);
+ padding:8px 14px;
+ border-radius:8px;
+ cursor:pointer;
+ color:#222;
+ font-weight:600;
+ transition: all 0.2s ease;
+}
+.controls button:hover:not(:disabled){
+ background:rgba(255,111,145,0.1);
+ border-color:rgba(255,111,145,0.3);
+ transform:translateY(-1px);
+}
+.controls button:active:not(:disabled){
+ transform:translateY(0);
+}
+.controls button:focus-visible{
+ outline: 2px solid var(--accent);
+ outline-offset: 2px;
+}
+.controls button:disabled{opacity:.4;cursor:not-allowed}
+.status{padding:6px 10px;border-radius:8px;background:rgba(255,255,255,0.6);margin-left:8px}
+.status.recording{
+ animation: recordPulse 1s ease-in-out infinite;
+ background:rgba(255,99,99,0.3);
+ color:#c42;
+ font-weight:600;
+}
+.hint{color:#5a3b4d;margin-top:10px}
+
+.volume-control{
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ gap:10px;
+ margin:16px 0 8px 0;
+ font-size:0.95rem;
+}
+.volume-control label{
+ font-weight:600;
+ color:#5a3b4d;
+}
+.volume-control input[type="range"]{
+ width:180px;
+ height:6px;
+ border-radius:3px;
+ background:rgba(255,111,145,0.2);
+ outline:none;
+ -webkit-appearance:none;
+ appearance:none;
+}
+.volume-control input[type="range"]::-webkit-slider-thumb{
+ -webkit-appearance:none;
+ appearance:none;
+ width:18px;
+ height:18px;
+ border-radius:50%;
+ background:var(--accent);
+ cursor:pointer;
+ transition:transform 0.15s ease;
+}
+.volume-control input[type="range"]::-webkit-slider-thumb:hover{
+ transform:scale(1.15);
+}
+.volume-control input[type="range"]::-moz-range-thumb{
+ width:18px;
+ height:18px;
+ border-radius:50%;
+ background:var(--accent);
+ cursor:pointer;
+ border:none;
+}
+#volume-value{
+ min-width:42px;
+ font-weight:600;
+ color:#666;
+}
+
+@media (max-width:520px){
+ .drum{width:44%;height:86px}
+}
+
+/* small animation for visual pulse */
+.pulse{
+ animation: pulse 360ms ease-out;
+}
+@keyframes pulse{
+ 0%{box-shadow:0 8px 30px rgba(255,111,145,0.15)}
+ 100%{box-shadow:0 8px 20px rgba(0,0,0,0.08)}
+}
+
+@keyframes recordPulse{
+ 0%, 100%{opacity:1}
+ 50%{opacity:0.6}
+}