ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/Jennys-Drumste / drum-teacher-pro.html

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/Jennys-Drumste / drum-teacher-pro.html
DateNot specified in source
RepositoryJanady13/Jennys-Drumste
Revisionc601bf1648fe71058835589331c7f7e669940b8b
Branchmain
Path or archive memberdrum-teacher-pro.html
Original SHA-256f1cb6620699816d00f043caa08d760396b543d928b13ab36002de2b01bd155e4
Git blob SHA1e5e63c6435077c051d5583d3e8f6d874288bcab
Reading-copy SHA-256f1cb6620699816d00f043caa08d760396b543d928b13ab36002de2b01bd155e4

Original source ↗

Every recorded occurrence

These 2 records contain identical original source bytes. Their paths and revisions remain part of the archive.

Original recordBranch or archiveRevision / identifierOriginal location
Janady13/Jennys-Drumste / drum-teacher-pro.htmlmainc601bf1648fe71058835589331c7f7e669940b8bOpen original
Janady13/Jennys-Drumste / drum-teacher-pro.htmlclaude/complete-integration-feature-011CUkTzyyk8bKmXaRXJAR6101c36ac1a180916e11864b4573b8c1999e2c5db3Open original

Recovered source transcript

Download complete source text ↓1,802 lines · 61.3 KB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DrumMaster Pro - Advanced Drum Learning System</title> <style> @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Inter:wght@300;400;600;700&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } :root { --primary: #00ffcc; --secondary: #ff00ff; --accent: #ffff00; --dark: #0a0a0f; --darker: #050508; --light: #ffffff; --success: #00ff88; --error: #ff0044; --warning: #ffaa00; } body { font-family: 'Inter', sans-serif; background: var(--darker); min-height: 100vh; color: var(--light); overflow-x: hidden; position: relative; } /* Animated background */ .bg-animation { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: radial-gradient(circle at 20% 50%, rgba(0, 255, 204, 0.1) 0%, transparent 50%), radial-gradient(circle at 80% 50%, rgba(255, 0, 255, 0.1) 0%, transparent 50%), radial-gradient(circle at 50% 100%, rgba(255, 255, 0, 0.05) 0%, transparent 50%); z-index: -2; animation: bgPulse 10s ease-in-out infinite; } @keyframes bgPulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } } .particles { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; } .particle { position: absolute; width: 2px; height: 2px; background: var(--primary); opacity: 0; animation: float 10s linear infinite; } @keyframes float { 0% { transform: translateY(100vh) translateX(0); opacity: 0; } 10% { opacity: 1; } 90% { opacity: 1; } 100% { transform: translateY(-100vh) translateX(100px); opacity: 0; } } /* Header */ header { background: linear-gradient(135deg, rgba(10, 10, 15, 0.95), rgba(5, 5, 8, 0.95)); backdrop-filter: blur(20px); border-bottom: 1px solid rgba(0, 255, 204, 0.2); padding: 20px; position: relative; z-index: 100; } .header-content { max-width: 1600px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center; } h1 { font-family: 'Orbitron', monospace; font-size: 2.5em; font-weight: 900; background: linear-gradient(135deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-shadow: 0 0 40px rgba(0, 255, 204, 0.5); } .connection-hub { display: flex; align-items: center; gap: 20px; } .connection-status { padding: 12px 24px; background: rgba(0, 255, 204, 0.1); border: 1px solid rgba(0, 255, 204, 0.3); border-radius: 50px; font-size: 0.9em; display: flex; align-items: center; gap: 10px; transition: all 0.3s; } .connection-status.connected { background: rgba(0, 255, 136, 0.2); border-color: var(--success); box-shadow: 0 0 20px rgba(0, 255, 136, 0.3); } .pulse-dot { width: 8px; height: 8px; background: var(--error); border-radius: 50%; animation: pulse 2s infinite; } .pulse-dot.active { background: var(--success); } @keyframes pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.5); opacity: 0.5; } } /* Main Layout */ .app-container { max-width: 1600px; margin: 0 auto; padding: 30px 20px; display: grid; grid-template-columns: 1fr 3fr 1fr; gap: 30px; } /* Left Panel */ .left-panel { display: flex; flex-direction: column; gap: 20px; } .panel-section { background: linear-gradient(135deg, rgba(10, 10, 15, 0.8), rgba(5, 5, 8, 0.8)); backdrop-filter: blur(10px); border: 1px solid rgba(0, 255, 204, 0.1); border-radius: 20px; padding: 20px; position: relative; overflow: hidden; } .panel-section::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: linear-gradient(90deg, transparent, var(--primary), transparent); animation: shimmer 3s infinite; } @keyframes shimmer { 0%, 100% { transform: translateX(-100%); } 50% { transform: translateX(100%); } } .section-title { font-family: 'Orbitron', monospace; font-size: 1.1em; font-weight: 700; color: var(--primary); margin-bottom: 15px; text-transform: uppercase; letter-spacing: 2px; } /* Modern Buttons */ .btn { background: linear-gradient(135deg, rgba(0, 255, 204, 0.1), rgba(255, 0, 255, 0.1)); border: 1px solid rgba(0, 255, 204, 0.3); color: var(--light); padding: 12px 24px; border-radius: 12px; cursor: pointer; font-size: 1em; font-weight: 600; transition: all 0.3s; position: relative; overflow: hidden; } .btn::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: radial-gradient(circle, var(--primary), transparent); transition: width 0.3s, height 0.3s; transform: translate(-50%, -50%); } .btn:hover { transform: translateY(-2px); box-shadow: 0 10px 30px rgba(0, 255, 204, 0.3); border-color: var(--primary); } .btn:hover::before { width: 200px; height: 200px; } .btn.primary { background: linear-gradient(135deg, var(--primary), var(--secondary)); border: none; color: var(--dark); font-weight: 700; } .btn:disabled { opacity: 0.3; cursor: not-allowed; } /* Drum Kit Visualization */ .drum-kit-container { background: linear-gradient(135deg, rgba(10, 10, 15, 0.9), rgba(5, 5, 8, 0.9)); border-radius: 30px; padding: 30px; border: 1px solid rgba(0, 255, 204, 0.1); position: relative; } .drum-kit-3d { perspective: 1000px; margin: 20px 0; } .drum-kit { display: grid; grid-template-areas: "crash hihat hihat ride" "tom1 tom1 tom2 tom2" "snare snare tom3 tom3" "kick kick kick kick"; gap: 15px; transform-style: preserve-3d; animation: floatKit 6s ease-in-out infinite; } @keyframes floatKit { 0%, 100% { transform: rotateX(5deg) rotateY(-5deg); } 50% { transform: rotateX(5deg) rotateY(5deg); } } .drum-pad { background: linear-gradient(135deg, rgba(20, 20, 30, 0.9), rgba(10, 10, 20, 0.9)); border: 2px solid rgba(0, 255, 204, 0.2); border-radius: 15px; padding: 20px; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; transition: all 0.3s; position: relative; overflow: hidden; min-height: 100px; } .drum-pad[data-name="Crash"] { grid-area: crash; } .drum-pad[data-name="Hi-Hat"] { grid-area: hihat; } .drum-pad[data-name="Ride"] { grid-area: ride; } .drum-pad[data-name="Tom 1"] { grid-area: tom1; } .drum-pad[data-name="Tom 2"] { grid-area: tom2; } .drum-pad[data-name="Tom 3"] { grid-area: tom3; } .drum-pad[data-name="Snare"] { grid-area: snare; } .drum-pad[data-name="Kick"] { grid-area: kick; } .drum-pad .drum-name { font-weight: 700; font-size: 1.1em; margin-bottom: 5px; } .drum-pad .drum-icon { font-size: 2em; margin-bottom: 5px; } .drum-pad .velocity-bar { width: 100%; height: 4px; background: rgba(0, 0, 0, 0.3); border-radius: 2px; overflow: hidden; margin-top: 10px; } .velocity-fill { height: 100%; background: linear-gradient(90deg, var(--success), var(--primary)); width: 0%; transition: width 0.1s; } .drum-pad.active { animation: drumHit 0.3s; border-color: var(--primary); box-shadow: 0 0 30px rgba(0, 255, 204, 0.6); } @keyframes drumHit { 0% { transform: scale(1) translateZ(0); } 50% { transform: scale(1.15) translateZ(20px); } 100% { transform: scale(1) translateZ(0); } } .drum-pad.target { animation: targetPulse 0.5s infinite; border-color: var(--accent); background: linear-gradient(135deg, rgba(255, 255, 0, 0.1), rgba(255, 165, 0, 0.1)); } @keyframes targetPulse { 0%, 100% { box-shadow: 0 0 20px rgba(255, 255, 0, 0.4); transform: scale(1); } 50% { box-shadow: 0 0 40px rgba(255, 255, 0, 0.8); transform: scale(1.05); } } .drum-pad.hit-perfect { animation: perfectHit 0.5s; background: linear-gradient(135deg, rgba(0, 255, 136, 0.3), rgba(0, 255, 204, 0.3)); } .drum-pad.hit-good { animation: goodHit 0.5s; background: linear-gradient(135deg, rgba(0, 255, 204, 0.2), rgba(0, 136, 255, 0.2)); } .drum-pad.hit-miss { animation: missHit 0.5s; background: linear-gradient(135deg, rgba(255, 0, 68, 0.2), rgba(255, 0, 136, 0.2)); } @keyframes perfectHit { 0% { transform: scale(1) rotateZ(0); } 50% { transform: scale(1.3) rotateZ(5deg); } 100% { transform: scale(1) rotateZ(0); } } @keyframes goodHit { 0% { transform: scale(1); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } } @keyframes missHit { 0% { transform: translateX(0); } 25% { transform: translateX(-10px); } 75% { transform: translateX(10px); } 100% { transform: translateX(0); } } /* Pattern Visualizer */ .pattern-visualizer { background: rgba(0, 0, 0, 0.5); border-radius: 15px; padding: 20px; margin: 20px 0; height: 200px; position: relative; overflow: hidden; } .pattern-grid { display: grid; grid-template-rows: repeat(9, 1fr); height: 100%; position: relative; } .pattern-track { display: flex; align-items: center; border-bottom: 1px solid rgba(0, 255, 204, 0.1); position: relative; } .track-label { width: 60px; font-size: 0.8em; color: var(--primary); font-weight: 600; } .track-timeline { flex: 1; height: 100%; position: relative; } .beat-marker { position: absolute; width: 10px; height: 10px; background: var(--accent); border-radius: 50%; top: 50%; transform: translateY(-50%); box-shadow: 0 0 10px rgba(255, 255, 0, 0.5); } .playhead { position: absolute; width: 2px; height: 100%; background: linear-gradient(180deg, transparent, var(--primary), transparent); left: 0; animation: movePlayhead 2s linear infinite; box-shadow: 0 0 20px var(--primary); } @keyframes movePlayhead { from { left: 0; } to { left: 100%; } } /* Right Panel - Stats */ .right-panel { display: flex; flex-direction: column; gap: 20px; } .stat-card { background: linear-gradient(135deg, rgba(10, 10, 15, 0.8), rgba(5, 5, 8, 0.8)); border: 1px solid rgba(0, 255, 204, 0.1); border-radius: 15px; padding: 15px; text-align: center; position: relative; overflow: hidden; } .stat-label { font-size: 0.9em; color: rgba(255, 255, 255, 0.6); margin-bottom: 5px; text-transform: uppercase; letter-spacing: 1px; } .stat-value { font-family: 'Orbitron', monospace; font-size: 2em; font-weight: 700; background: linear-gradient(135deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .stat-chart { margin-top: 10px; height: 40px; position: relative; } .mini-bars { display: flex; align-items: flex-end; height: 100%; gap: 2px; } .mini-bar { flex: 1; background: linear-gradient(180deg, var(--primary), rgba(0, 255, 204, 0.3)); border-radius: 2px; transition: height 0.3s; } /* Achievement System */ .achievements { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 15px; } .achievement { width: 50px; height: 50px; background: linear-gradient(135deg, rgba(20, 20, 30, 0.9), rgba(10, 10, 20, 0.9)); border: 2px solid rgba(0, 255, 204, 0.1); border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.5em; cursor: pointer; transition: all 0.3s; position: relative; } .achievement.unlocked { border-color: var(--accent); background: linear-gradient(135deg, rgba(255, 255, 0, 0.1), rgba(255, 165, 0, 0.1)); animation: achievementUnlock 0.5s; } @keyframes achievementUnlock { 0% { transform: scale(0) rotateZ(0); } 50% { transform: scale(1.2) rotateZ(180deg); } 100% { transform: scale(1) rotateZ(360deg); } } .achievement-tooltip { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: var(--dark); color: var(--light); padding: 5px 10px; border-radius: 5px; font-size: 0.8em; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 0.3s; } .achievement:hover .achievement-tooltip { opacity: 1; } /* Recording Controls */ .recording-panel { display: flex; gap: 10px; margin-top: 20px; } .record-btn { background: linear-gradient(135deg, rgba(255, 0, 68, 0.2), rgba(255, 0, 136, 0.2)); border-color: rgba(255, 0, 68, 0.5); } .record-btn.recording { animation: recordPulse 1s infinite; background: linear-gradient(135deg, rgba(255, 0, 68, 0.4), rgba(255, 0, 136, 0.4)); } @keyframes recordPulse { 0%, 100% { box-shadow: 0 0 20px rgba(255, 0, 68, 0.5); } 50% { box-shadow: 0 0 40px rgba(255, 0, 68, 0.8); } } /* Performance Graph */ .performance-graph { height: 150px; background: rgba(0, 0, 0, 0.3); border-radius: 10px; padding: 10px; position: relative; margin-top: 20px; } .graph-canvas { width: 100%; height: 100%; } /* Modal */ .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.9); backdrop-filter: blur(10px); z-index: 1000; align-items: center; justify-content: center; } .modal.active { display: flex; animation: fadeIn 0.3s; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .modal-content { background: linear-gradient(135deg, rgba(10, 10, 15, 0.95), rgba(5, 5, 8, 0.95)); border: 1px solid var(--primary); border-radius: 30px; padding: 40px; max-width: 600px; text-align: center; animation: slideUp 0.3s; } @keyframes slideUp { from { transform: translateY(50px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .modal h2 { font-family: 'Orbitron', monospace; font-size: 2em; background: linear-gradient(135deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 20px; } /* Lesson Selector */ .lesson-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-top: 15px; } .lesson-card { background: rgba(0, 255, 204, 0.05); border: 1px solid rgba(0, 255, 204, 0.2); border-radius: 10px; padding: 10px; cursor: pointer; transition: all 0.3s; } .lesson-card:hover { background: rgba(0, 255, 204, 0.1); transform: translateY(-2px); } .lesson-card.active { background: rgba(0, 255, 204, 0.2); border-color: var(--primary); } .lesson-card .lesson-name { font-weight: 600; font-size: 0.9em; margin-bottom: 5px; } .lesson-card .lesson-difficulty { font-size: 0.8em; color: rgba(255, 255, 255, 0.6); } .difficulty-stars { color: var(--accent); } /* Tempo Control */ .tempo-control { display: flex; align-items: center; gap: 15px; margin-top: 15px; } .tempo-slider { flex: 1; -webkit-appearance: none; height: 6px; background: rgba(0, 255, 204, 0.1); border-radius: 3px; outline: none; } .tempo-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 20px; height: 20px; background: var(--primary); border-radius: 50%; cursor: pointer; box-shadow: 0 0 10px var(--primary); } .tempo-display { font-family: 'Orbitron', monospace; font-size: 1.2em; color: var(--primary); min-width: 80px; } /* Sound Toggle */ .sound-toggle { display: flex; align-items: center; gap: 10px; margin-top: 15px; } .toggle-switch { width: 50px; height: 25px; background: rgba(0, 255, 204, 0.1); border-radius: 25px; position: relative; cursor: pointer; transition: background 0.3s; } .toggle-switch.active { background: var(--primary); } .toggle-knob { width: 21px; height: 21px; background: var(--light); border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: transform 0.3s; } .toggle-switch.active .toggle-knob { transform: translateX(25px); } /* Loading Animation */ .loader { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 2000; } .loader.active { display: block; } .loader-circle { width: 60px; height: 60px; border: 3px solid rgba(0, 255, 204, 0.1); border-top-color: var(--primary); border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } @media (max-width: 1200px) { .app-container { grid-template-columns: 1fr; } .left-panel, .right-panel { grid-template-columns: repeat(2, 1fr); display: grid; } } </style> </head> <body> <div class="bg-animation"></div> <div class="particles" id="particles"></div> <header> <div class="header-content"> <h1>🥁 DrumMaster Pro</h1> <div class="connection-hub"> <div class="connection-status" id="connectionStatus"> <span class="pulse-dot" id="pulseDot"></span> <span id="statusText">Disconnected - Click Connect</span> </div> <button class="btn primary" id="connectBtn">Connect MIDI</button> </div> </div> </header> <div class="app-container"> <!-- Left Panel --> <div class="left-panel"> <!-- Controls --> <div class="panel-section"> <h3 class="section-title">Controls</h3> <div style="display: flex; flex-direction: column; gap: 10px;"> <button class="btn primary" id="startBtn" disabled>Start Session</button> <button class="btn" id="stopBtn" disabled>Stop</button> <button class="btn" id="freePlayBtn">Free Play</button> <button class="btn" id="metronomeBtn">Metronome</button> </div> </div> <!-- Lessons --> <div class="panel-section"> <h3 class="section-title">Training Modules</h3> <div class="lesson-grid" id="lessonGrid"> <!-- Lessons will be populated here --> </div> </div> <!-- Tempo --> <div class="panel-section"> <h3 class="section-title">Tempo</h3> <div class="tempo-control"> <input type="range" class="tempo-slider" id="tempoSlider" min="40" max="200" value="90"> <span class="tempo-display" id="tempoDisplay">90 BPM</span> </div> <div class="sound-toggle"> <span>Click Track</span> <div class="toggle-switch" id="clickToggle"> <div class="toggle-knob"></div> </div> </div> </div> <!-- Recording --> <div class="panel-section"> <h3 class="section-title">Recording</h3> <div class="recording-panel"> <button class="btn record-btn" id="recordBtn">⏺ Record</button> <button class="btn" id="playbackBtn" disabled>▶ Play</button> <button class="btn" id="saveBtn" disabled>💾 Save</button> </div> </div> </div> <!-- Center - Drum Kit --> <div class="center-panel"> <div class="drum-kit-container"> <div class="pattern-visualizer"> <div class="pattern-grid" id="patternGrid"> <div class="playhead" id="playhead"></div> <!-- Pattern tracks will be populated here --> </div> </div> <div class="drum-kit-3d"> <div class="drum-kit" id="drumKit"> <div class="drum-pad" data-note="49" data-name="Crash"> <span class="drum-icon">💥</span> <span class="drum-name">Crash</span> <div class="velocity-bar"><div class="velocity-fill"></div></div> </div> <div class="drum-pad" data-note="46" data-name="Hi-Hat"> <span class="drum-icon">🎩</span> <span class="drum-name">Hi-Hat</span> <div class="velocity-bar"><div class="velocity-fill"></div></div> </div> <div class="drum-pad" data-note="51" data-name="Ride"> <span class="drum-icon">🔔</span> <span class="drum-name">Ride</span> <div class="velocity-bar"><div class="velocity-fill"></div></div> </div> <div class="drum-pad" data-note="48" data-name="Tom 1"> <span class="drum-icon">🥁</span> <span class="drum-name">Tom 1</span> <div class="velocity-bar"><div class="velocity-fill"></div></div> </div> <div class="drum-pad" data-note="45" data-name="Tom 2"> <span class="drum-icon">🥁</span> <span class="drum-name">Tom 2</span> <div class="velocity-bar"><div class="velocity-fill"></div></div> </div> <div class="drum-pad" data-note="43" data-name="Tom 3"> <span class="drum-icon">🥁</span> <span class="drum-name">Tom 3</span> <div class="velocity-bar"><div class="velocity-fill"></div></div> </div> <div class="drum-pad" data-note="38" data-name="Snare"> <span class="drum-icon">🎵</span> <span class="drum-name">Snare</span> <div class="velocity-bar"><div class="velocity-fill"></div></div> </div> <div class="drum-pad" data-note="36" data-name="Kick"> <span class="drum-icon">🦶</span> <span class="drum-name">Kick</span> <div class="velocity-bar"><div class="velocity-fill"></div></div> </div> </div> </div> <div class="performance-graph"> <canvas class="graph-canvas" id="performanceGraph"></canvas> </div> </div> </div> <!-- Right Panel - Stats --> <div class="right-panel"> <div class="stat-card"> <div class="stat-label">Accuracy</div> <div class="stat-value" id="accuracy">0%</div> <div class="stat-chart"> <div class="mini-bars" id="accuracyBars"></div> </div> </div> <div class="stat-card"> <div class="stat-label">Combo</div> <div class="stat-value" id="combo">0</div> <div class="stat-chart"> <div class="mini-bars" id="comboBars"></div> </div> </div> <div class="stat-card"> <div class="stat-label">Score</div> <div class="stat-value" id="score">0</div> </div> <div class="stat-card"> <div class="stat-label">Session Time</div> <div class="stat-value" id="sessionTime">0:00</div> </div> <div class="panel-section"> <h3 class="section-title">Achievements</h3> <div class="achievements" id="achievements"> <!-- Achievements will be populated here --> </div> </div> <div class="panel-section"> <h3 class="section-title">Leaderboard</h3> <div id="leaderboard"> <div style="text-align: center; color: rgba(255,255,255,0.5); padding: 20px;"> Coming Soon </div> </div> </div> </div> </div> <!-- Modal --> <div class="modal" id="modal"> <div class="modal-content"> <h2 id="modalTitle">Session Complete!</h2> <div id="modalBody"></div> <button class="btn primary" onclick="closeModal()">Continue</button> </div> </div> <div class="loader" id="loader"> <div class="loader-circle"></div> </div> <script> // Advanced Lesson System const LESSONS = { basic: { name: 'Fundamentals', difficulty: 1, icon: '📚', patterns: [ { time: 0, drum: 36 }, { time: 500, drum: 38 }, { time: 1000, drum: 36 }, { time: 1500, drum: 38 } ], duration: 2000 }, groove: { name: 'Pocket Groove', difficulty: 2, icon: '🎸', patterns: [ { time: 0, drum: 36 }, { time: 0, drum: 46 }, { time: 250, drum: 46 }, { time: 500, drum: 38 }, { time: 500, drum: 46 }, { time: 750, drum: 46 }, { time: 1000, drum: 36 }, { time: 1000, drum: 46 }, { time: 1250, drum: 46 }, { time: 1500, drum: 38 }, { time: 1500, drum: 46 }, { time: 1750, drum: 46 } ], duration: 2000 }, funk: { name: 'Funk Pattern', difficulty: 3, icon: '🎷', patterns: [ { time: 0, drum: 36 }, { time: 0, drum: 46 }, { time: 125, drum: 46 }, { time: 250, drum: 38 }, { time: 250, drum: 46 }, { time: 375, drum: 36 }, { time: 500, drum: 46 }, { time: 625, drum: 38 }, { time: 625, drum: 46 }, { time: 750, drum: 46 }, { time: 875, drum: 36 }, { time: 1000, drum: 46 }, { time: 1125, drum: 38 }, { time: 1250, drum: 46 }, { time: 1375, drum: 36 }, { time: 1500, drum: 46 }, { time: 1625, drum: 38 }, { time: 1750, drum: 46 } ], duration: 2000 }, jazz: { name: 'Jazz Swing', difficulty: 4, icon: '🎺', patterns: [ { time: 0, drum: 51 }, { time: 333, drum: 51 }, { time: 500, drum: 51 }, { time: 666, drum: 51 }, { time: 1000, drum: 51 }, { time: 1333, drum: 51 }, { time: 1500, drum: 51 }, { time: 1666, drum: 51 }, { time: 250, drum: 36 }, { time: 750, drum: 38 }, { time: 1250, drum: 36 }, { time: 1750, drum: 38 } ], duration: 2000 }, metal: { name: 'Metal Blast', difficulty: 5, icon: '🤘', patterns: [ { time: 0, drum: 36 }, { time: 0, drum: 49 }, { time: 125, drum: 36 }, { time: 250, drum: 38 }, { time: 375, drum: 36 }, { time: 500, drum: 36 }, { time: 625, drum: 38 }, { time: 750, drum: 36 }, { time: 875, drum: 36 }, { time: 1000, drum: 38 }, { time: 1125, drum: 36 }, { time: 1250, drum: 36 }, { time: 1375, drum: 38 }, { time: 1500, drum: 36 }, { time: 1625, drum: 36 }, { time: 1750, drum: 38 } ], duration: 2000 }, latin: { name: 'Latin Rhythms', difficulty: 3, icon: '💃', patterns: [ { time: 0, drum: 36 }, { time: 0, drum: 51 }, { time: 187, drum: 51 }, { time: 375, drum: 51 }, { time: 500, drum: 38 }, { time: 500, drum: 51 }, { time: 687, drum: 51 }, { time: 875, drum: 51 }, { time: 1000, drum: 36 }, { time: 1000, drum: 51 }, { time: 1187, drum: 51 }, { time: 1375, drum: 51 }, { time: 1500, drum: 38 }, { time: 1500, drum: 51 }, { time: 1687, drum: 51 }, { time: 1875, drum: 51 } ], duration: 2000 }, paradiddle: { name: 'Paradiddles', difficulty: 4, icon: '🔄', patterns: [ { time: 0, drum: 38 }, { time: 125, drum: 38 }, { time: 250, drum: 38 }, { time: 375, drum: 38 }, { time: 500, drum: 38 }, { time: 625, drum: 38 }, { time: 750, drum: 38 }, { time: 875, drum: 38 } ], duration: 1000 }, ghost: { name: 'Ghost Notes', difficulty: 4, icon: '👻', patterns: [ { time: 0, drum: 36 }, { time: 125, drum: 38, velocity: 30 }, { time: 250, drum: 38, velocity: 30 }, { time: 375, drum: 38 }, { time: 500, drum: 36 }, { time: 625, drum: 38, velocity: 30 }, { time: 750, drum: 38, velocity: 30 }, { time: 875, drum: 38 }, { time: 1000, drum: 36 }, { time: 1125, drum: 38, velocity: 30 }, { time: 1250, drum: 36 }, { time: 1375, drum: 38 }, { time: 1500, drum: 38, velocity: 30 }, { time: 1625, drum: 38, velocity: 30 }, { time: 1750, drum: 38 } ], duration: 2000 } }; // Achievement System const ACHIEVEMENTS = [ { id: 'first_hit', name: 'First Hit', icon: '🎯', condition: () => stats.totalHits >= 1 }, { id: 'combo_10', name: 'Combo x10', icon: '🔥', condition: () => stats.maxCombo >= 10 }, { id: 'combo_50', name: 'Combo x50', icon: '💥', condition: () => stats.maxCombo >= 50 }, { id: 'perfect_run', name: 'Perfect Run', icon: '⭐', condition: () => stats.perfectRuns >= 1 }, { id: 'speed_demon', name: 'Speed Demon', icon: '⚡', condition: () => stats.maxBPM >= 160 }, { id: 'marathon', name: 'Marathon', icon: '🏃', condition: () => stats.sessionTime >= 1800 }, { id: 'accuracy_master', name: 'Accuracy Master', icon: '🎯', condition: () => stats.sessionAccuracy >= 95 }, { id: 'all_drums', name: 'Kit Master', icon: '🥁', condition: () => stats.drumsUsed.size >= 8 }, { id: 'level_10', name: 'Level 10', icon: '🏆', condition: () => stats.level >= 10 } ]; // Global State let midiAccess = null; let midiInput = null; let audioContext = null; let isPlaying = false; let isRecording = false; let currentLesson = 'basic'; let bpm = 90; let clickEnabled = false; let metronomeInterval = null; let sessionStartTime = null; let recordedPattern = []; let performanceHistory = []; // Statistics let stats = { accuracy: 0, combo: 0, maxCombo: 0, score: 0, totalHits: 0, perfectHits: 0, goodHits: 0, missedHits: 0, sessionTime: 0, sessionAccuracy: 0, perfectRuns: 0, maxBPM: 90, drumsUsed: new Set(), level: 1, unlockedAchievements: new Set() }; // Initialize document.addEventListener('DOMContentLoaded', () => { initParticles(); initLessons(); initAchievements(); initEventListeners(); initAudioContext(); updateStats(); startSessionTimer(); initPerformanceGraph(); }); function initParticles() { const container = document.getElementById('particles'); for (let i = 0; i < 50; i++) { const particle = document.createElement('div'); particle.className = 'particle'; particle.style.left = Math.random() * 100 + '%'; particle.style.animationDelay = Math.random() * 10 + 's'; particle.style.animationDuration = (10 + Math.random() * 10) + 's'; container.appendChild(particle); } } function initLessons() { const grid = document.getElementById('lessonGrid'); for (const [key, lesson] of Object.entries(LESSONS)) { const card = document.createElement('div'); card.className = 'lesson-card'; card.dataset.lesson = key; card.innerHTML = ` <div class="lesson-name">${lesson.icon} ${lesson.name}</div> <div class="lesson-difficulty"> <span class="difficulty-stars">${'★'.repeat(lesson.difficulty)}${'☆'.repeat(5 - lesson.difficulty)}</span> </div> `; card.addEventListener('click', () => selectLesson(key)); grid.appendChild(card); } selectLesson('basic'); } function selectLesson(lessonKey) { currentLesson = lessonKey; document.querySelectorAll('.lesson-card').forEach(card => { card.classList.toggle('active', card.dataset.lesson === lessonKey); }); visualizePattern(LESSONS[lessonKey]); } function visualizePattern(lesson) { const grid = document.getElementById('patternGrid'); const drums = [49, 51, 46, 48, 45, 43, 38, 41, 36]; const drumNames = ['Crash', 'Ride', 'Hi-Hat', 'Tom1', 'Tom2', 'Tom3', 'Snare', 'Floor', 'Kick']; grid.innerHTML = '<div class="playhead" id="playhead"></div>'; drums.forEach((note, index) => { const track = document.createElement('div'); track.className = 'pattern-track'; track.innerHTML = `<div class="track-label">${drumNames[index]}</div><div class="track-timeline" data-note="${note}"></div>`; grid.appendChild(track); const timeline = track.querySelector('.track-timeline'); lesson.patterns.forEach(beat => { if (beat.drum === note) { const marker = document.createElement('div'); marker.className = 'beat-marker'; marker.style.left = (beat.time / lesson.duration * 100) + '%'; timeline.appendChild(marker); } }); }); } function initAchievements() { const container = document.getElementById('achievements'); ACHIEVEMENTS.forEach(achievement => { const elem = document.createElement('div'); elem.className = 'achievement'; elem.dataset.id = achievement.id; elem.innerHTML = ` ${achievement.icon} <div class="achievement-tooltip">${achievement.name}</div> `; container.appendChild(elem); }); } function initEventListeners() { document.getElementById('connectBtn').addEventListener('click', connectMIDI); document.getElementById('startBtn').addEventListener('click', startSession); document.getElementById('stopBtn').addEventListener('click', stopSession); document.getElementById('freePlayBtn').addEventListener('click', toggleFreePlay); document.getElementById('metronomeBtn').addEventListener('click', toggleMetronome); document.getElementById('recordBtn').addEventListener('click', toggleRecording); document.getElementById('playbackBtn').addEventListener('click', playbackRecording); document.getElementById('tempoSlider').addEventListener('input', updateTempo); document.getElementById('clickToggle').addEventListener('click', toggleClick); // Keyboard support document.addEventListener('keydown', handleKeyboard); } function initAudioContext() { audioContext = new (window.AudioContext || window.webkitAudioContext)(); } async function connectMIDI() { const loader = document.getElementById('loader'); loader.classList.add('active'); try { midiAccess = await navigator.requestMIDIAccess(); const inputs = midiAccess.inputs.values(); for (let input of inputs) { midiInput = input; midiInput.onmidimessage = handleMIDIMessage; break; } if (midiInput) { updateConnectionStatus(true, midiInput.name || 'MIDI Device'); document.getElementById('startBtn').disabled = false; playSuccessAnimation(); } else { updateConnectionStatus(false, 'No device found'); } } catch (error) { console.error('MIDI connection failed:', error); updateConnectionStatus(false, 'MIDI not supported'); } finally { loader.classList.remove('active'); } } function updateConnectionStatus(connected, message) { const status = document.getElementById('connectionStatus'); const statusText = document.getElementById('statusText'); const pulseDot = document.getElementById('pulseDot'); const connectBtn = document.getElementById('connectBtn'); if (connected) { status.classList.add('connected'); pulseDot.classList.add('active'); statusText.textContent = `Connected: ${message}`; connectBtn.textContent = 'Connected'; connectBtn.disabled = true; } else { status.classList.remove('connected'); pulseDot.classList.remove('active'); statusText.textContent = message; } } function handleMIDIMessage(message) { const [status, note, velocity] = message.data; if (status >= 144 && status <= 159 && velocity > 0) { handleDrumHit(note, velocity); } } function handleDrumHit(note, velocity) { // Visual feedback const pad = document.querySelector(`.drum-pad[data-note="${note}"]`); if (pad) { pad.classList.add('active'); const velocityFill = pad.querySelector('.velocity-fill'); velocityFill.style.width = (velocity / 127 * 100) + '%'; setTimeout(() => { pad.classList.remove('active'); velocityFill.style.width = '0%'; }, 300); } // Update statistics stats.totalHits++; stats.drumsUsed.add(note); if (isRecording) { recordedPattern.push({ time: performance.now(), note: note, velocity: velocity }); } if (isPlaying) { checkAccuracy(note, velocity); } updateStats(); checkAchievements(); } function checkAccuracy(note, velocity) { // Check timing accuracy const tolerance = 100; // ms const now = performance.now(); // Implementation would check against expected pattern timing // For demo, simulate accuracy const random = Math.random(); if (random > 0.7) { stats.perfectHits++; stats.combo++; stats.score += 100 * (1 + stats.combo * 0.1); showHitFeedback('perfect'); } else if (random > 0.3) { stats.goodHits++; stats.combo++; stats.score += 50; showHitFeedback('good'); } else { stats.missedHits++; stats.combo = 0; showHitFeedback('miss'); } stats.maxCombo = Math.max(stats.maxCombo, stats.combo); updateAccuracy(); } function showHitFeedback(type) { // Visual feedback for hit quality const pad = document.querySelector('.drum-pad.active'); if (pad) { pad.classList.remove('hit-perfect', 'hit-good', 'hit-miss'); pad.classList.add(`hit-${type}`); } } function updateAccuracy() { const total = stats.perfectHits + stats.goodHits + stats.missedHits; if (total > 0) { stats.accuracy = Math.round(((stats.perfectHits + stats.goodHits) / total) * 100); stats.sessionAccuracy = stats.accuracy; } // Update accuracy chart performanceHistory.push(stats.accuracy); if (performanceHistory.length > 20) performanceHistory.shift(); updateAccuracyBars(); } function updateAccuracyBars() { const bars = document.getElementById('accuracyBars'); bars.innerHTML = ''; performanceHistory.forEach(value => { const bar = document.createElement('div'); bar.className = 'mini-bar'; bar.style.height = value + '%'; bars.appendChild(bar); }); } function startSession() { isPlaying = true; sessionStartTime = Date.now(); document.getElementById('startBtn').disabled = true; document.getElementById('stopBtn').disabled = false; // Start pattern playback for selected lesson playPattern(LESSONS[currentLesson]); } function stopSession() { isPlaying = false; document.getElementById('startBtn').disabled = false; document.getElementById('stopBtn').disabled = true; // Show session results showSessionResults(); }

Search equations, builds, manuscript text, and recovered sources.