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
Revision1f946b9e18e552f80f4b2ffd7f59c01d0126aa53
Branchclaude/jenny-drumsets-research-MofSb
Path or archive memberdrum-teacher-pro.html
Original SHA-256cb2280313c4a369b914802b8cd1fdc59a2d2d84b12563414e138caf0f865bd9d
Git blob SHA9ba6dfad3fc0301c7eb6934dc5d36c1aff30c9e2
Reading-copy SHA-256cb2280313c4a369b914802b8cd1fdc59a2d2d84b12563414e138caf0f865bd9d

Original source ↗

Recovered source transcript

Download complete source text ↓2,033 lines · 69.1 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 - SEFERIM AGI Rock Band Style</title> <script src="seferim-core.js"></script> <style> @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Russo+One&family=Press+Start+2P&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } :root { --kick-color: #ff3366; --snare-color: #ffcc00; --hihat-color: #00ccff; --crash-color: #ff9900; --tom1-color: #cc33ff; --tom2-color: #33ff66; --tom3-color: #ff6633; --ride-color: #3366ff; --primary: #00ffcc; --secondary: #ff00ff; --accent: #ffcc00; --dark: #0a0a15; --success: #00ff88; --danger: #ff3366; } body { font-family: 'Orbitron', sans-serif; background: var(--dark); color: white; overflow: hidden; height: 100vh; user-select: none; } /* Main Game Container */ .game-container { display: grid; grid-template-columns: 200px 1fr 280px; height: 100vh; gap: 0; } /* Left Panel - Stats */ .stats-panel { background: linear-gradient(180deg, rgba(0,0,0,0.9) 0%, rgba(20,0,40,0.9) 100%); padding: 20px; display: flex; flex-direction: column; gap: 15px; border-right: 2px solid rgba(255,0,255,0.3); } .logo { font-family: 'Russo One', sans-serif; font-size: 1.2em; text-align: center; background: linear-gradient(135deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px; } /* Score Display */ .score-container { background: rgba(0,0,0,0.5); border: 2px solid var(--primary); border-radius: 10px; padding: 15px; text-align: center; } .score-label { font-size: 0.7em; color: rgba(255,255,255,0.6); text-transform: uppercase; letter-spacing: 2px; } .score-value { font-family: 'Press Start 2P', monospace; font-size: 1.5em; color: var(--accent); text-shadow: 0 0 20px var(--accent); } /* Multiplier */ .multiplier-container { text-align: center; padding: 10px; } .multiplier-label { font-size: 0.6em; color: rgba(255,255,255,0.5); } .multiplier-value { font-size: 2.5em; font-weight: 900; background: linear-gradient(135deg, var(--accent), var(--danger)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-shadow: 0 0 30px rgba(255,204,0,0.5); } .multiplier-bar { height: 8px; background: rgba(255,255,255,0.1); border-radius: 4px; margin-top: 5px; overflow: hidden; } .multiplier-fill { height: 100%; background: linear-gradient(90deg, var(--primary), var(--accent)); border-radius: 4px; transition: width 0.2s; } /* Combo Display */ .combo-container { text-align: center; padding: 15px; background: rgba(0,0,0,0.3); border-radius: 10px; } .combo-value { font-size: 3em; font-weight: 900; color: var(--success); text-shadow: 0 0 30px var(--success); transition: transform 0.1s; } .combo-value.bump { transform: scale(1.3); } .combo-label { font-size: 0.8em; color: var(--success); letter-spacing: 3px; } /* Star Power */ .star-power-container { padding: 15px; background: linear-gradient(135deg, rgba(255,204,0,0.1), rgba(255,102,0,0.1)); border: 2px solid rgba(255,204,0,0.3); border-radius: 10px; text-align: center; } .star-power-label { font-size: 0.7em; color: var(--accent); letter-spacing: 2px; margin-bottom: 8px; } .star-power-bar { height: 20px; background: rgba(0,0,0,0.5); border-radius: 10px; overflow: hidden; position: relative; } .star-power-fill { height: 100%; background: linear-gradient(90deg, #ff6600, #ffcc00, #ff6600); background-size: 200% 100%; animation: starPowerShine 2s linear infinite; transition: width 0.3s; } .star-power-fill.active { animation: starPowerActive 0.5s linear infinite; } @keyframes starPowerShine { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } @keyframes starPowerActive { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.5); } } .star-power-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 0.6em; font-weight: bold; color: white; text-shadow: 0 0 5px black; } /* Accuracy */ .accuracy-container { text-align: center; padding: 10px; } .accuracy-value { font-size: 1.8em; font-weight: bold; } .accuracy-value.perfect { color: var(--success); } .accuracy-value.great { color: var(--primary); } .accuracy-value.good { color: var(--accent); } .accuracy-value.poor { color: var(--danger); } /* Center Panel - Note Highway */ .highway-panel { position: relative; background: linear-gradient(180deg, #000 0%, #0a0020 50%, #150030 100%); overflow: hidden; } /* Stage Background */ .stage-background { position: absolute; top: 0; left: 0; right: 0; height: 30%; background: radial-gradient(ellipse at center bottom, rgba(255,0,255,0.2) 0%, transparent 70%); pointer-events: none; } .stage-lights { position: absolute; top: 0; left: 0; right: 0; height: 200px; display: flex; justify-content: space-around; pointer-events: none; } .stage-light { width: 100px; height: 300px; background: linear-gradient(180deg, rgba(255,255,255,0.3) 0%, transparent 100%); clip-path: polygon(30% 0%, 70% 0%, 100% 100%, 0% 100%); opacity: 0.3; animation: lightPulse 2s ease-in-out infinite; } .stage-light:nth-child(1) { animation-delay: 0s; background: linear-gradient(180deg, rgba(255,0,100,0.4) 0%, transparent 100%); } .stage-light:nth-child(2) { animation-delay: 0.5s; background: linear-gradient(180deg, rgba(0,255,200,0.4) 0%, transparent 100%); } .stage-light:nth-child(3) { animation-delay: 1s; background: linear-gradient(180deg, rgba(255,200,0,0.4) 0%, transparent 100%); } .stage-light:nth-child(4) { animation-delay: 1.5s; background: linear-gradient(180deg, rgba(100,0,255,0.4) 0%, transparent 100%); } @keyframes lightPulse { 0%, 100% { opacity: 0.2; } 50% { opacity: 0.5; } } /* Note Highway Canvas */ .highway-canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } /* Hit Zone */ .hit-zone { position: absolute; bottom: 80px; left: 0; right: 0; height: 60px; display: flex; justify-content: center; gap: 10px; z-index: 10; } .hit-pad { width: 80px; height: 60px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 0.6em; font-weight: bold; text-transform: uppercase; transition: all 0.05s; position: relative; overflow: hidden; } .hit-pad::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: inherit; filter: blur(20px); opacity: 0.5; z-index: -1; } .hit-pad[data-drum="kick"] { background: linear-gradient(180deg, var(--kick-color), #990033); border: 3px solid var(--kick-color); } .hit-pad[data-drum="snare"] { background: linear-gradient(180deg, var(--snare-color), #997700); border: 3px solid var(--snare-color); } .hit-pad[data-drum="hihat"] { background: linear-gradient(180deg, var(--hihat-color), #006699); border: 3px solid var(--hihat-color); } .hit-pad[data-drum="crash"] { background: linear-gradient(180deg, var(--crash-color), #995500); border: 3px solid var(--crash-color); } .hit-pad[data-drum="tom1"] { background: linear-gradient(180deg, var(--tom1-color), #660099); border: 3px solid var(--tom1-color); } .hit-pad[data-drum="tom2"] { background: linear-gradient(180deg, var(--tom2-color), #009933); border: 3px solid var(--tom2-color); } .hit-pad[data-drum="ride"] { background: linear-gradient(180deg, var(--ride-color), #003399); border: 3px solid var(--ride-color); } .hit-pad.hit { transform: scale(1.2); box-shadow: 0 0 40px currentColor; } .hit-pad .key-hint { position: absolute; bottom: -20px; font-size: 0.7em; color: rgba(255,255,255,0.5); } /* Hit Effects Container */ .effects-container { position: absolute; top: 0; left: 0; right: 0; bottom: 0; pointer-events: none; z-index: 20; } /* Explosion Effect */ .explosion { position: absolute; width: 150px; height: 150px; pointer-events: none; animation: explode 0.4s ease-out forwards; } @keyframes explode { 0% { transform: scale(0.5); opacity: 1; } 100% { transform: scale(2); opacity: 0; } } /* Hit Judgment */ .hit-judgment { position: absolute; font-family: 'Russo One', sans-serif; font-size: 2em; font-weight: bold; text-shadow: 0 0 20px currentColor; animation: judgeFloat 0.6s ease-out forwards; z-index: 30; } .hit-judgment.perfect { color: var(--success); } .hit-judgment.great { color: var(--primary); } .hit-judgment.good { color: var(--accent); } .hit-judgment.miss { color: var(--danger); } @keyframes judgeFloat { 0% { transform: translateY(0) scale(1.5); opacity: 1; } 100% { transform: translateY(-80px) scale(1); opacity: 0; } } /* Streak Flames */ .streak-flames { position: absolute; bottom: 140px; left: 50%; transform: translateX(-50%); width: 600px; height: 100px; display: flex; justify-content: center; gap: 5px; opacity: 0; transition: opacity 0.3s; z-index: 5; } .streak-flames.active { opacity: 1; } .flame { width: 30px; background: linear-gradient(180deg, transparent, var(--accent), var(--danger)); border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%; animation: flameFlicker 0.2s ease-in-out infinite alternate; } @keyframes flameFlicker { 0% { transform: scaleY(0.8) scaleX(1); opacity: 0.8; } 100% { transform: scaleY(1.2) scaleX(0.9); opacity: 1; } } /* Crowd Meter */ .crowd-meter { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); width: 400px; z-index: 30; } .crowd-label { text-align: center; font-size: 0.7em; color: rgba(255,255,255,0.6); margin-bottom: 5px; } .crowd-bar { height: 15px; background: rgba(0,0,0,0.5); border-radius: 8px; overflow: hidden; border: 2px solid rgba(255,255,255,0.2); } .crowd-fill { height: 100%; transition: width 0.5s, background 0.3s; border-radius: 6px; } .crowd-fill.danger { background: linear-gradient(90deg, #ff0000, #ff3333); } .crowd-fill.warning { background: linear-gradient(90deg, #ff6600, #ffcc00); } .crowd-fill.good { background: linear-gradient(90deg, #00cc66, #00ff88); } .crowd-fill.great { background: linear-gradient(90deg, #00ffcc, #00ff88); animation: crowdPulse 0.5s infinite; } @keyframes crowdPulse { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.3); } } /* Song Info */ .song-info { position: absolute; top: 50px; left: 50%; transform: translateX(-50%); text-align: center; z-index: 30; } .song-title { font-family: 'Russo One', sans-serif; font-size: 1.5em; color: white; text-shadow: 0 0 20px var(--primary); } .song-artist { font-size: 0.9em; color: rgba(255,255,255,0.6); } /* Controls Bar */ .controls-bar { position: absolute; bottom: 0; left: 0; right: 0; height: 60px; background: linear-gradient(180deg, transparent, rgba(0,0,0,0.9)); display: flex; justify-content: center; align-items: center; gap: 20px; z-index: 30; } .control-btn { padding: 10px 25px; font-family: 'Orbitron', sans-serif; font-size: 0.9em; border: 2px solid var(--primary); background: rgba(0,255,204,0.1); color: var(--primary); border-radius: 25px; cursor: pointer; transition: all 0.2s; } .control-btn:hover { background: var(--primary); color: var(--dark); box-shadow: 0 0 30px var(--primary); } .control-btn.active { background: var(--primary); color: var(--dark); } /* BPM Display */ .bpm-display { font-size: 1.2em; color: var(--accent); } /* Right Panel - SEFERIM & Settings */ .right-panel { background: linear-gradient(180deg, rgba(0,0,0,0.9) 0%, rgba(0,20,40,0.9) 100%); padding: 15px; display: flex; flex-direction: column; gap: 15px; border-left: 2px solid rgba(0,255,204,0.3); overflow-y: auto; } /* Lesson Selector */ .lesson-selector { background: rgba(0,0,0,0.3); border-radius: 10px; padding: 15px; } .lesson-label { font-size: 0.7em; color: rgba(255,255,255,0.5); margin-bottom: 10px; text-transform: uppercase; letter-spacing: 1px; } .lesson-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } .lesson-btn { padding: 10px; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; color: white; font-size: 0.7em; cursor: pointer; transition: all 0.2s; text-align: left; } .lesson-btn:hover { background: rgba(0,255,204,0.1); border-color: var(--primary); } .lesson-btn.active { background: rgba(0,255,204,0.2); border-color: var(--primary); box-shadow: 0 0 15px rgba(0,255,204,0.3); } .lesson-btn .difficulty { display: inline-block; margin-top: 5px; } .lesson-btn .difficulty span { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: rgba(255,255,255,0.2); margin-right: 2px; } .lesson-btn .difficulty span.filled { background: var(--accent); } /* SEFERIM Panel */ .seferim-panel { background: linear-gradient(135deg, rgba(10, 10, 20, 0.95), rgba(0, 20, 40, 0.95)); border: 1px solid rgba(0, 255, 204, 0.3); border-radius: 12px; padding: 15px; } .seferim-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .seferim-title { font-size: 0.8em; color: var(--primary); letter-spacing: 1px; } .seferim-version { font-size: 0.6em; color: rgba(0,255,204,0.5); background: rgba(0,255,204,0.1); padding: 2px 6px; border-radius: 6px; } .seferim-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-bottom: 12px; } .seferim-stat { text-align: center; padding: 8px; background: rgba(0,0,0,0.3); border-radius: 6px; } .seferim-stat-value { font-size: 1.1em; color: var(--primary); font-weight: bold; } .seferim-stat-label { font-size: 0.55em; color: rgba(255,255,255,0.4); text-transform: uppercase; } .families-mini { display: grid; grid-template-columns: repeat(8, 1fr); gap: 3px; } .family-bar { height: 25px; background: rgba(0,255,204,0.1); border-radius: 3px; position: relative; overflow: hidden; } .family-bar-fill { position: absolute; bottom: 0; left: 0; right: 0; background: linear-gradient(180deg, var(--primary), rgba(0,255,204,0.5)); transition: height 0.3s; } .family-bar.active { box-shadow: 0 0 10px var(--secondary); } /* Tempo Control */ .tempo-control { background: rgba(0,0,0,0.3); border-radius: 10px; padding: 15px; } .tempo-label { font-size: 0.7em; color: rgba(255,255,255,0.5); margin-bottom: 8px; } .tempo-slider { width: 100%; height: 8px; -webkit-appearance: none; background: rgba(255,255,255,0.1); border-radius: 4px; 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-value { text-align: center; font-size: 1.5em; color: var(--accent); margin-top: 8px; } /* MIDI Status */ .midi-status { display: flex; align-items: center; gap: 10px; padding: 10px; background: rgba(0,0,0,0.3); border-radius: 8px; } .midi-dot { width: 12px; height: 12px; border-radius: 50%; background: var(--danger); } .midi-dot.connected { background: var(--success); animation: midiPulse 1s infinite; } @keyframes midiPulse { 0%, 100% { box-shadow: 0 0 5px var(--success); } 50% { box-shadow: 0 0 15px var(--success); } } .midi-text { font-size: 0.75em; color: rgba(255,255,255,0.7); } /* Practice Mode Toggle */ .practice-mode { display: flex; align-items: center; justify-content: space-between; padding: 12px; background: rgba(0,0,0,0.3); border-radius: 8px; } .practice-label { font-size: 0.75em; color: rgba(255,255,255,0.7); } .toggle-switch { width: 50px; height: 26px; background: rgba(255,255,255,0.1); border-radius: 13px; position: relative; cursor: pointer; transition: background 0.3s; } .toggle-switch.active { background: var(--primary); } .toggle-switch::after { content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; background: white; border-radius: 50%; transition: left 0.3s; } .toggle-switch.active::after { left: 27px; } /* Countdown Overlay */ .countdown-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.8); display: none; align-items: center; justify-content: center; z-index: 100; } .countdown-overlay.active { display: flex; } .countdown-number { font-family: 'Press Start 2P', monospace; font-size: 8em; color: var(--primary); text-shadow: 0 0 50px var(--primary); animation: countdownPulse 1s ease-out; } @keyframes countdownPulse { 0% { transform: scale(2); opacity: 0; } 50% { transform: scale(1); opacity: 1; } 100% { transform: scale(0.8); opacity: 0; } } /* Game Over Screen */ .game-over-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.9); display: none; flex-direction: column; align-items: center; justify-content: center; z-index: 100; } .game-over-overlay.active { display: flex; } .results-card { background: linear-gradient(135deg, rgba(20,0,40,0.95), rgba(0,40,60,0.95)); border: 2px solid var(--primary); border-radius: 20px; padding: 40px; text-align: center; max-width: 500px; } .results-title { font-family: 'Russo One', sans-serif; font-size: 2.5em; margin-bottom: 20px; background: linear-gradient(135deg, var(--primary), var(--accent)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .results-score { font-family: 'Press Start 2P', monospace; font-size: 3em; color: var(--accent); margin-bottom: 30px; } .results-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-bottom: 30px; } .result-stat { text-align: center; } .result-stat-value { font-size: 2em; font-weight: bold; color: var(--primary); } .result-stat-label { font-size: 0.8em; color: rgba(255,255,255,0.6); } .star-rating { font-size: 3em; margin-bottom: 20px; } .star-rating .star { color: rgba(255,255,255,0.2); margin: 0 5px; transition: color 0.3s; } .star-rating .star.filled { color: var(--accent); text-shadow: 0 0 20px var(--accent); } /* Responsive */ @media (max-width: 1200px) { .game-container { grid-template-columns: 150px 1fr 200px; } } @media (max-width: 900px) { .game-container { grid-template-columns: 1fr; } .stats-panel, .right-panel { display: none; } } </style> </head> <body> <div class="game-container"> <!-- Left Panel - Stats --> <div class="stats-panel"> <div class="logo">DRUMMASTER PRO</div> <div class="score-container"> <div class="score-label">Score</div> <div class="score-value" id="scoreDisplay">0</div> </div> <div class="multiplier-container"> <div class="multiplier-label">Multiplier</div> <div class="multiplier-value" id="multiplierDisplay">1x</div> <div class="multiplier-bar"> <div class="multiplier-fill" id="multiplierFill" style="width: 0%"></div> </div> </div> <div class="combo-container"> <div class="combo-value" id="comboDisplay">0</div> <div class="combo-label">COMBO</div> </div> <div class="star-power-container"> <div class="star-power-label">STAR POWER</div> <div class="star-power-bar"> <div class="star-power-fill" id="starPowerFill" style="width: 0%"></div> <div class="star-power-text" id="starPowerText">0%</div> </div> </div> <div class="accuracy-container"> <div class="score-label">Accuracy</div> <div class="accuracy-value good" id="accuracyDisplay">100%</div> </div> <div class="midi-status"> <div class="midi-dot" id="midiDot"></div> <div class="midi-text" id="midiText">No MIDI Connected</div> </div> </div> <!-- Center Panel - Highway --> <div class="highway-panel"> <div class="stage-background"></div> <div class="stage-lights"> <div class="stage-light"></div> <div class="stage-light"></div> <div class="stage-light"></div> <div class="stage-light"></div> </div> <canvas class="highway-canvas" id="highwayCanvas"></canvas> <div class="crowd-meter"> <div class="crowd-label">CROWD</div> <div class="crowd-bar"> <div class="crowd-fill good" id="crowdFill" style="width: 50%"></div> </div> </div> <div class="song-info"> <div class="song-title" id="songTitle">Basic Rock Beat</div> <div class="song-artist" id="songArtist">Lesson 1</div> </div> <div class="streak-flames" id="streakFlames"> <div class="flame" style="height: 60px;"></div> <div class="flame" style="height: 80px;"></div> <div class="flame" style="height: 100px;"></div> <div class="flame" style="height: 80px;"></div> <div class="flame" style="height: 60px;"></div> </div> <div class="hit-zone" id="hitZone"> <div class="hit-pad" data-drum="kick"><span>KICK</span><span class="key-hint">SPACE</span></div> <div class="hit-pad" data-drum="snare"><span>SNARE</span><span class="key-hint">S</span></div> <div class="hit-pad" data-drum="hihat"><span>HI-HAT</span><span class="key-hint">H</span></div> <div class="hit-pad" data-drum="crash"><span>CRASH</span><span class="key-hint">C</span></div> <div class="hit-pad" data-drum="tom1"><span>TOM 1</span><span class="key-hint">1</span></div> <div class="hit-pad" data-drum="tom2"><span>TOM 2</span><span class="key-hint">2</span></div> <div class="hit-pad" data-drum="ride"><span>RIDE</span><span class="key-hint">R</span></div> </div> <div class="effects-container" id="effectsContainer"></div> <div class="controls-bar"> <button class="control-btn" id="playBtn" onclick="togglePlay()">PLAY</button> <button class="control-btn" onclick="restartSong()">RESTART</button> <div class="bpm-display"><span id="bpmValue">120</span> BPM</div> <button class="control-btn" onclick="activateStarPower()" id="starPowerBtn">STAR POWER (TAB)</button> </div> </div> <!-- Right Panel --> <div class="right-panel"> <div class="lesson-selector"> <div class="lesson-label">Select Lesson</div> <div class="lesson-grid" id="lessonGrid"> <!-- Generated by JS --> </div> </div> <div class="tempo-control"> <div class="tempo-label">TEMPO</div> <input type="range" class="tempo-slider" id="tempoSlider" min="40" max="200" value="120"> <div class="tempo-value"><span id="tempoValue">120</span> BPM</div> </div> <div class="practice-mode"> <span class="practice-label">Practice Mode (No Fail)</span> <div class="toggle-switch" id="practiceModeToggle" onclick="togglePracticeMode()"></div> </div> <!-- SEFERIM Panel --> <div class="seferim-panel"> <div class="seferim-header"> <span class="seferim-title">SEFERIM AGI</span> <span class="seferim-version">G16 v3.1.1</span> </div> <div class="seferim-stats"> <div class="seferim-stat"> <div class="seferim-stat-value" id="seferimPhi">0.00</div> <div class="seferim-stat-label">Global Φ</div> </div> <div class="seferim-stat"> <div class="seferim-stat-value" id="seferimK">0</div> <div class="seferim-stat-label">Knowledge</div> </div> <div class="seferim-stat"> <div class="seferim-stat-value" id="seferimTick">0</div> <div class="seferim-stat-label">Ticks</div> </div> <div class="seferim-stat"> <div class="seferim-stat-value" id="seferimLevel">1</div> <div class="seferim-stat-label">Level</div> </div> </div> <div class="families-mini" id="familiesMini"> <!-- Generated by JS --> </div> </div> </div> </div> <!-- Countdown Overlay --> <div class="countdown-overlay" id="countdownOverlay"> <div class="countdown-number" id="countdownNumber">3</div> </div> <!-- Game Over Overlay --> <div class="game-over-overlay" id="gameOverOverlay"> <div class="results-card"> <div class="results-title">SONG COMPLETE!</div> <div class="star-rating" id="starRating"> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> </div> <div class="results-score" id="finalScore">0</div> <div class="results-stats"> <div class="result-stat"> <div class="result-stat-value" id="finalAccuracy">0%</div> <div class="result-stat-label">Accuracy</div> </div> <div class="result-stat"> <div class="result-stat-value" id="finalCombo">0</div> <div class="result-stat-label">Max Combo</div> </div> <div class="result-stat"> <div class="result-stat-value" id="finalStreak">0</div> <div class="result-stat-label">Note Streak</div> </div> </div> <button class="control-btn" onclick="closeResults()">CONTINUE</button> </div> </div> <script> // ═══════════════════════════════════════════════════════════════════════════════ // ROCK BAND STYLE DRUM GAME ENGINE // ═══════════════════════════════════════════════════════════════════════════════ // Game State const gameState = { isPlaying: false, isPracticeMode: false, score: 0, combo: 0, maxCombo: 0, multiplier: 1, multiplierProgress: 0, starPower: 0, starPowerActive: false, accuracy: 100, totalNotes: 0, hitNotes: 0, perfectNotes: 0, greatNotes: 0, goodNotes: 0, missedNotes: 0, crowdMeter: 50, bpm: 120, currentLesson: 0, noteSpeed: 400, // pixels per second songPosition: 0, lastBeatTime: 0 }; // Lessons Data const lessons = [ { name: "Basic Rock", artist: "Lesson 1", difficulty: 1, bpm: 100, pattern: { kick: "1---1---1---1---", snare: "----1-------1---", hihat: "1-1-1-1-1-1-1-1-" } }, { name: "Disco Beat", artist: "Lesson 2", difficulty: 2, bpm: 110, pattern: { kick: "1---1---1---1---", snare: "----1-------1---", hihat: "1111111111111111" } }, { name: "Funk Groove", artist: "Lesson 3", difficulty: 3, bpm: 95, pattern: { kick: "1--1--1---1-1---", snare: "----1--1----1---", hihat: "1-1-1-1-1-1-1-1-" } }, { name: "Metal Drive", artist: "Lesson 4", difficulty: 4, bpm: 140, pattern: { kick: "1-1-1-1-1-1-1-1-", snare: "----1-------1---", hihat: "1111111111111111" } }, { name: "Jazz Swing", artist: "Lesson 5", difficulty: 3, bpm: 130, pattern: { kick: "1-------1-------", snare: "----1-------1---", ride: "1--1--1-1--1--1-" } }, { name: "Drum Fill", artist: "Lesson 6", difficulty: 4, bpm: 100, pattern: { kick: "1-------1-------", snare: "----1-----------", tom1: "--------1-1-----", tom2: "------------1-1-" } }, { name: "Double Bass", artist: "Lesson 7", difficulty: 5, bpm: 160, pattern: { kick: "1111111111111111", snare: "----1-------1---", hihat: "1---1---1---1---" } }, { name: "Polyrhythm", artist: "Lesson 8", difficulty: 5, bpm: 90, pattern: { kick: "1--1--1--1--1--1", snare: "----1-------1---", hihat: "1-1-1-1-1-1-1-1-", ride: "--1---1---1---1-" } } ]; // Note colors const drumColors = { kick: '#ff3366', snare: '#ffcc00', hihat: '#00ccff', crash: '#ff9900', tom1: '#cc33ff', tom2: '#33ff66', tom3: '#ff6633', ride: '#3366ff' }; // Key mappings const keyMap = { ' ': 'kick', 's': 'snare', 'h': 'hihat', 'c': 'crash', '1': 'tom1', '2': 'tom2', '3': 'tom3', 'r': 'ride' }; // MIDI note mappings const midiMap = { 36: 'kick', 38: 'snare', 42: 'hihat', 46: 'hihat', 49: 'crash', 48: 'tom1', 45: 'tom2', 43: 'tom3', 51: 'ride' }; // Notes on highway let activeNotes = []; let canvas, ctx; let animationId; let lastTime = 0; // Lane positions const lanes = ['kick', 'snare', 'hihat', 'crash', 'tom1', 'tom2', 'ride']; let lanePositions = {}; // ═══════════════════════════════════════════════════════════════════════════════ // INITIALIZATION // ═══════════════════════════════════════════════════════════════════════════════ document.addEventListener('DOMContentLoaded', () => { initCanvas(); initLessons(); initMIDI(); initSeferim(); selectLesson(0); window.addEventListener('resize', initCanvas); }); function initCanvas() { canvas = document.getElementById('highwayCanvas'); ctx = canvas.getContext('2d'); canvas.width = canvas.offsetWidth * 2; canvas.height = canvas.offsetHeight * 2; ctx.scale(2, 2); // Calculate lane positions based on hit pads const hitZone = document.getElementById('hitZone'); const pads = hitZone.querySelectorAll('.hit-pad'); const containerRect = canvas.getBoundingClientRect(); pads.forEach((pad, index) => { const padRect = pad.getBoundingClientRect(); const centerX = (padRect.left + padRect.width / 2) - containerRect.left; lanePositions[pad.dataset.drum] = centerX; }); } function initLessons() { const grid = document.getElementById('lessonGrid'); grid.innerHTML = ''; lessons.forEach((lesson, index) => { const btn = document.createElement('button'); btn.className = 'lesson-btn'; btn.onclick = () => selectLesson(index); btn.innerHTML = ` <div>${lesson.name}</div> <div class="difficulty"> ${Array(5).fill(0).map((_, i) => `<span class="${i < lesson.difficulty ? 'filled' : ''}"></span>` ).join('')} </div> `; grid.appendChild(btn); }); } function selectLesson(index) { gameState.currentLesson = index; const lesson = lessons[index]; document.getElementById('songTitle').textContent = lesson.name; document.getElementById('songArtist').textContent = lesson.artist; document.getElementById('bpmValue').textContent = lesson.bpm; gameState.bpm = lesson.bpm; document.getElementById('tempoSlider').value = lesson.bpm; document.getElementById('tempoValue').textContent = lesson.bpm; // Update active lesson button document.querySelectorAll('.lesson-btn').forEach((btn, i) => { btn.classList.toggle('active', i === index); }); // Stop current game and reset if (gameState.isPlaying) { stopGame(); } resetGame(); } // ═══════════════════════════════════════════════════════════════════════════════ // MIDI HANDLING // ═══════════════════════════════════════════════════════════════════════════════ function initMIDI() { if (navigator.requestMIDIAccess) { navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure); } else { console.log('WebMIDI not supported'); } } function onMIDISuccess(midiAccess) { for (let input of midiAccess.inputs.values()) { input.onmidimessage = handleMIDIMessage; } midiAccess.onstatechange = (e) => { if (e.port.state === 'connected' && e.port.type === 'input') { e.port.onmidimessage = handleMIDIMessage; updateMIDIStatus(true, e.port.name); } }; if (midiAccess.inputs.size > 0) { const firstInput = midiAccess.inputs.values().next().value; updateMIDIStatus(true, firstInput.name); } } function onMIDIFailure() { console.log('Could not access MIDI devices'); } function handleMIDIMessage(message) { const [status, note, velocity] = message.data; if (status >= 144 && status <= 159 && velocity > 0) { const drumType = midiMap[note]; if (drumType) { handleDrumHit(drumType, velocity); } } } function updateMIDIStatus(connected, name) { const dot = document.getElementById('midiDot'); const text = document.getElementById('midiText'); dot.classList.toggle('connected', connected); text.textContent = connected ? name : 'No MIDI Connected'; } // ═══════════════════════════════════════════════════════════════════════════════ // KEYBOARD HANDLING // ═══════════════════════════════════════════════════════════════════════════════ document.addEventListener('keydown', (e) => { const key = e.key.toLowerCase(); if (key === 'tab') { e.preventDefault(); activateStarPower(); return; } if (key === 'enter' || key === 'p') { e.preventDefault(); togglePlay(); return; } const drumType = keyMap[key]; if (drumType) { e.preventDefault(); handleDrumHit(drumType, 100); } }); // ═══════════════════════════════════════════════════════════════════════════════ // DRUM HIT HANDLING // ═══════════════════════════════════════════════════════════════════════════════ function handleDrumHit(drumType, velocity) { // Visual feedback on pad const pad = document.querySelector(`.hit-pad[data-drum="${drumType}"]`); if (pad) { pad.classList.add('hit'); setTimeout(() => pad.classList.remove('hit'), 100); } // Check for note hit const hitResult = checkNoteHit(drumType); // Create hit effect createHitEffect(drumType, hitResult); // Process through SEFERIM if (window.SEFERIM) { window.SEFERIM.processDrumHit( drumType, velocity, performance.now(), performance.now(), lessons[gameState.currentLesson].name ); updateSeferimUI(); } updateUI(); } function checkNoteHit(drumType) { const hitWindow = 100; // ms const perfectWindow = 30; const greatWindow = 60; const lane = lanePositions[drumType]; const hitY = canvas.offsetHeight - 110; let closestNote = null; let closestDist = Infinity; for (let i = activeNotes.length - 1; i >= 0; i--) { const note = activeNotes[i]; if (note.drum === drumType && !note.hit) { const dist = Math.abs(note.y - hitY); if (dist < closestDist) { closestDist = dist; closestNote = note; } } } if (closestNote && closestDist < hitWindow) { closestNote.hit = true; let judgment, points; if (closestDist < perfectWindow) { judgment = 'perfect';

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