Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/Jennys-Drumste / drum-song-mode.html |
| Date | Not specified in source |
| Repository | Janady13/Jennys-Drumste |
| Revision | 1f946b9e18e552f80f4b2ffd7f59c01d0126aa53 |
| Branch | claude/jenny-drumsets-research-MofSb |
| Path or archive member | drum-song-mode.html |
| Original SHA-256 | d7aba45b3ca504f9004367b79999d660be2d8149c9d02bc2b5d42f5672265f71 |
| Git blob SHA | 92a12b2ca0d295d0bdf89ed61c443add258483d2 |
| Reading-copy SHA-256 | d7aba45b3ca504f9004367b79999d660be2d8149c9d02bc2b5d42f5672265f71 |
Recovered source transcript
Download complete source text ↓2,622 lines · 94.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 - Rock Band Song Mode | YouTube Integration</title>
<script src="seferim-core.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=Orbitron:wght@400;700;900&family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--kick-color: #ff6b35;
--snare-color: #f7c948;
--hihat-color: #4ecdc4;
--crash-color: #ff006e;
--tom1-color: #8338ec;
--tom2-color: #3a86ff;
--ride-color: #06ffa5;
--star-power: #00d4ff;
--bg-dark: #0a0a12;
--bg-darker: #050508;
--neon-pink: #ff00ff;
--neon-cyan: #00ffff;
--neon-green: #00ff88;
}
body {
font-family: 'Inter', sans-serif;
background: var(--bg-darker);
color: white;
overflow: hidden;
height: 100vh;
}
/* Main Layout */
.game-container {
display: grid;
grid-template-columns: 300px 1fr 280px;
grid-template-rows: auto 1fr;
height: 100vh;
gap: 10px;
padding: 10px;
background: linear-gradient(180deg, #1a0a2e 0%, #0a0a12 50%, #0d1520 100%);
}
/* Header */
.header {
grid-column: 1 / -1;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
background: linear-gradient(90deg, rgba(255,0,255,0.1), rgba(0,255,255,0.1));
border: 1px solid rgba(255,0,255,0.3);
border-radius: 10px;
}
.logo {
font-family: 'Press Start 2P', cursive;
font-size: 1.2em;
background: linear-gradient(90deg, var(--neon-pink), var(--neon-cyan));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 30px rgba(255,0,255,0.5);
}
.header-stats {
display: flex;
gap: 30px;
align-items: center;
}
.header-stat {
text-align: center;
}
.header-stat-value {
font-family: 'Orbitron', sans-serif;
font-size: 1.5em;
font-weight: 900;
color: var(--neon-cyan);
}
.header-stat-label {
font-size: 0.7em;
color: rgba(255,255,255,0.6);
text-transform: uppercase;
}
.multiplier {
font-family: 'Press Start 2P', cursive;
font-size: 1.2em;
padding: 8px 16px;
background: linear-gradient(135deg, #ff6b35, #f7c948);
border-radius: 8px;
color: #000;
}
/* Left Panel - Song Selection */
.song-panel {
background: rgba(10,10,20,0.9);
border: 1px solid rgba(0,255,255,0.2);
border-radius: 15px;
padding: 15px;
display: flex;
flex-direction: column;
gap: 10px;
overflow: hidden;
}
.panel-title {
font-family: 'Orbitron', sans-serif;
font-size: 1em;
color: var(--neon-cyan);
text-transform: uppercase;
letter-spacing: 2px;
padding-bottom: 10px;
border-bottom: 1px solid rgba(0,255,255,0.2);
}
/* YouTube Input Section */
.youtube-section {
background: rgba(255,0,0,0.1);
border: 1px solid rgba(255,0,0,0.3);
border-radius: 10px;
padding: 12px;
}
.youtube-input-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.youtube-input {
width: 100%;
padding: 10px;
background: rgba(0,0,0,0.5);
border: 1px solid rgba(255,0,0,0.3);
border-radius: 8px;
color: white;
font-size: 0.85em;
}
.youtube-input:focus {
outline: none;
border-color: #ff0000;
box-shadow: 0 0 10px rgba(255,0,0,0.3);
}
.btn {
padding: 10px 16px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
font-size: 0.85em;
}
.btn-youtube {
background: linear-gradient(135deg, #ff0000, #cc0000);
color: white;
}
.btn-youtube:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(255,0,0,0.4);
}
.btn-play {
background: linear-gradient(135deg, var(--neon-green), #00cc6a);
color: #000;
}
.btn-play:hover {
box-shadow: 0 5px 20px rgba(0,255,136,0.4);
}
/* BPM Controls */
.bpm-controls {
display: flex;
gap: 8px;
align-items: center;
margin-top: 8px;
}
.bpm-input {
width: 70px;
padding: 8px;
background: rgba(0,0,0,0.5);
border: 1px solid rgba(0,255,255,0.3);
border-radius: 6px;
color: var(--neon-cyan);
font-family: 'Orbitron', sans-serif;
text-align: center;
}
.bpm-label {
font-size: 0.75em;
color: rgba(255,255,255,0.6);
}
.btn-tap {
background: linear-gradient(135deg, var(--neon-pink), #cc00cc);
color: white;
flex: 1;
}
/* Song Library */
.song-library {
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 8px;
}
.song-card {
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 10px;
padding: 12px;
cursor: pointer;
transition: all 0.2s;
}
.song-card:hover {
background: rgba(0,255,255,0.05);
border-color: var(--neon-cyan);
transform: translateX(5px);
}
.song-card.active {
background: linear-gradient(135deg, rgba(0,255,255,0.1), rgba(255,0,255,0.1));
border-color: var(--neon-cyan);
}
.song-title {
font-weight: 600;
font-size: 0.9em;
margin-bottom: 4px;
}
.song-artist {
font-size: 0.75em;
color: rgba(255,255,255,0.5);
margin-bottom: 6px;
}
.song-meta {
display: flex;
gap: 10px;
font-size: 0.7em;
}
.song-bpm {
color: var(--neon-cyan);
}
.song-difficulty {
padding: 2px 8px;
border-radius: 10px;
font-size: 0.65em;
text-transform: uppercase;
}
.diff-easy { background: rgba(0,255,136,0.2); color: var(--neon-green); }
.diff-medium { background: rgba(247,201,72,0.2); color: #f7c948; }
.diff-hard { background: rgba(255,0,110,0.2); color: #ff006e; }
.diff-expert { background: rgba(131,56,236,0.2); color: #8338ec; }
/* Main Game Area */
.game-area {
display: flex;
flex-direction: column;
gap: 10px;
position: relative;
}
/* Video Player Container */
.video-container {
position: relative;
width: 100%;
height: 200px;
background: #000;
border-radius: 15px;
overflow: hidden;
border: 2px solid rgba(255,0,0,0.3);
}
#youtube-player {
width: 100%;
height: 100%;
}
.video-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
background: linear-gradient(180deg, transparent 60%, rgba(0,0,0,0.8) 100%);
}
.video-info {
position: absolute;
bottom: 10px;
left: 15px;
right: 15px;
display: flex;
justify-content: space-between;
align-items: flex-end;
pointer-events: none;
}
.now-playing {
font-size: 0.8em;
}
.now-playing-title {
font-weight: 700;
font-size: 1.1em;
}
.now-playing-artist {
color: rgba(255,255,255,0.6);
}
.video-time {
font-family: 'Orbitron', sans-serif;
font-size: 1.2em;
color: var(--neon-cyan);
}
/* Note Highway */
.highway-container {
flex: 1;
position: relative;
perspective: 1000px;
overflow: hidden;
border-radius: 15px;
background: linear-gradient(180deg, #0a0015 0%, #150025 50%, #0a0a12 100%);
border: 2px solid rgba(255,0,255,0.2);
}
#noteHighway {
width: 100%;
height: 100%;
display: block;
}
/* Hit Zone */
.hit-zone-container {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 100px;
display: flex;
justify-content: center;
align-items: flex-end;
padding-bottom: 10px;
background: linear-gradient(0deg, rgba(0,0,0,0.9) 0%, transparent 100%);
}
.hit-zone {
display: flex;
gap: 8px;
justify-content: center;
}
.drum-lane {
width: 60px;
height: 60px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5em;
border: 3px solid;
transition: all 0.1s;
position: relative;
cursor: pointer;
}
.drum-lane[data-drum="kick"] {
border-color: var(--kick-color);
background: rgba(255,107,53,0.1);
box-shadow: 0 0 20px rgba(255,107,53,0.3);
}
.drum-lane[data-drum="snare"] {
border-color: var(--snare-color);
background: rgba(247,201,72,0.1);
box-shadow: 0 0 20px rgba(247,201,72,0.3);
}
.drum-lane[data-drum="hihat"] {
border-color: var(--hihat-color);
background: rgba(78,205,196,0.1);
box-shadow: 0 0 20px rgba(78,205,196,0.3);
}
.drum-lane[data-drum="crash"] {
border-color: var(--crash-color);
background: rgba(255,0,110,0.1);
box-shadow: 0 0 20px rgba(255,0,110,0.3);
}
.drum-lane[data-drum="tom1"] {
border-color: var(--tom1-color);
background: rgba(131,56,236,0.1);
box-shadow: 0 0 20px rgba(131,56,236,0.3);
}
.drum-lane[data-drum="tom2"] {
border-color: var(--tom2-color);
background: rgba(58,134,255,0.1);
box-shadow: 0 0 20px rgba(58,134,255,0.3);
}
.drum-lane[data-drum="ride"] {
border-color: var(--ride-color);
background: rgba(6,255,165,0.1);
box-shadow: 0 0 20px rgba(6,255,165,0.3);
}
.drum-lane.hit {
transform: scale(0.9);
filter: brightness(2);
}
.drum-lane .key-hint {
position: absolute;
bottom: -20px;
font-size: 0.5em;
color: rgba(255,255,255,0.4);
font-family: 'Press Start 2P', cursive;
}
/* Right Panel */
.stats-panel {
background: rgba(10,10,20,0.9);
border: 1px solid rgba(255,0,255,0.2);
border-radius: 15px;
padding: 15px;
display: flex;
flex-direction: column;
gap: 15px;
}
/* Star Power Meter */
.star-power-section {
background: linear-gradient(135deg, rgba(0,212,255,0.1), rgba(0,100,200,0.1));
border: 1px solid var(--star-power);
border-radius: 12px;
padding: 12px;
}
.star-power-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.star-power-title {
font-family: 'Press Start 2P', cursive;
font-size: 0.6em;
color: var(--star-power);
}
.star-power-status {
font-size: 0.7em;
padding: 3px 8px;
border-radius: 10px;
background: rgba(0,212,255,0.2);
color: var(--star-power);
}
.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, #0066cc, var(--star-power), #00ffff);
width: 0%;
transition: width 0.3s;
position: relative;
}
.star-power-fill.ready {
animation: starPulse 0.5s infinite;
}
@keyframes starPulse {
0%, 100% { filter: brightness(1); }
50% { filter: brightness(1.5); }
}
.star-power-fill.active {
background: linear-gradient(90deg, #00ffff, #ffffff, #00ffff);
animation: starActive 0.3s infinite;
}
@keyframes starActive {
0%, 100% { filter: hue-rotate(0deg); }
50% { filter: hue-rotate(30deg); }
}
/* Crowd Meter */
.crowd-section {
background: rgba(255,255,255,0.02);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 12px;
padding: 12px;
}
.crowd-header {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
}
.crowd-title {
font-size: 0.75em;
color: rgba(255,255,255,0.6);
text-transform: uppercase;
}
.crowd-reaction {
font-size: 0.8em;
}
.crowd-bar {
height: 15px;
background: rgba(0,0,0,0.5);
border-radius: 8px;
overflow: hidden;
}
.crowd-fill {
height: 100%;
width: 50%;
transition: all 0.3s;
border-radius: 8px;
}
/* Score Display */
.score-section {
text-align: center;
padding: 15px;
background: linear-gradient(135deg, rgba(255,0,255,0.05), rgba(0,255,255,0.05));
border-radius: 12px;
border: 1px solid rgba(255,0,255,0.2);
}
.score-label {
font-size: 0.7em;
color: rgba(255,255,255,0.5);
text-transform: uppercase;
margin-bottom: 5px;
}
.score-value {
font-family: 'Orbitron', sans-serif;
font-size: 2em;
font-weight: 900;
background: linear-gradient(135deg, var(--neon-pink), var(--neon-cyan));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Combo & Streak */
.combo-section {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.stat-box {
background: rgba(0,0,0,0.3);
border-radius: 10px;
padding: 12px;
text-align: center;
}
.stat-box-value {
font-family: 'Orbitron', sans-serif;
font-size: 1.5em;
font-weight: 700;
}
.stat-box-label {
font-size: 0.65em;
color: rgba(255,255,255,0.5);
text-transform: uppercase;
}
.combo-value { color: var(--neon-green); }
.streak-value { color: var(--snare-color); }
.accuracy-value { color: var(--neon-cyan); }
.notes-value { color: var(--neon-pink); }
/* SEFERIM Panel */
.seferim-section {
background: linear-gradient(135deg, rgba(0,20,40,0.9), rgba(10,10,30,0.9));
border: 1px solid rgba(0,255,204,0.3);
border-radius: 12px;
padding: 12px;
}
.seferim-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.seferim-title {
font-family: 'Orbitron', sans-serif;
font-size: 0.7em;
color: #00ffcc;
letter-spacing: 1px;
}
.seferim-version {
font-size: 0.55em;
color: rgba(0,255,204,0.6);
background: rgba(0,255,204,0.1);
padding: 2px 6px;
border-radius: 6px;
}
.seferim-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
margin-bottom: 10px;
}
.seferim-stat {
text-align: center;
padding: 6px;
background: rgba(0,255,204,0.05);
border-radius: 6px;
}
.seferim-stat-value {
font-family: 'Orbitron', sans-serif;
font-size: 0.9em;
color: #00ffcc;
font-weight: 700;
}
.seferim-stat-label {
font-size: 0.5em;
color: rgba(255,255,255,0.4);
}
.seferim-families {
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(0deg, #00ffcc, rgba(0,255,204,0.5));
transition: height 0.3s;
}
.family-bar.active {
box-shadow: 0 0 8px #ff00ff;
}
/* Controls */
.controls-section {
display: flex;
flex-direction: column;
gap: 8px;
}
.btn-control {
width: 100%;
padding: 12px;
border-radius: 8px;
font-weight: 600;
font-size: 0.85em;
}
.btn-start {
background: linear-gradient(135deg, var(--neon-green), #00aa55);
color: #000;
font-family: 'Press Start 2P', cursive;
font-size: 0.7em;
}
.btn-practice {
background: linear-gradient(135deg, #3a86ff, #0066cc);
color: white;
}
.practice-toggle {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
background: rgba(255,255,255,0.03);
border-radius: 8px;
font-size: 0.8em;
}
.toggle-switch {
width: 50px;
height: 26px;
background: rgba(255,255,255,0.1);
border-radius: 13px;
position: relative;
cursor: pointer;
transition: all 0.3s;
}
.toggle-switch.active {
background: var(--neon-green);
}
.toggle-switch::after {
content: '';
position: absolute;
width: 22px;
height: 22px;
background: white;
border-radius: 50%;
top: 2px;
left: 2px;
transition: all 0.3s;
}
.toggle-switch.active::after {
left: 26px;
}
/* Judgment Display */
.judgment-display {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-family: 'Press Start 2P', cursive;
font-size: 2em;
pointer-events: none;
z-index: 100;
text-shadow: 0 0 20px currentColor;
opacity: 0;
transition: opacity 0.1s;
}
.judgment-display.show {
opacity: 1;
animation: judgmentPop 0.3s ease-out;
}
@keyframes judgmentPop {
0% { transform: translate(-50%, -50%) scale(0.5); }
50% { transform: translate(-50%, -50%) scale(1.2); }
100% { transform: translate(-50%, -50%) scale(1); }
}
.judgment-perfect { color: #00ffff; }
.judgment-great { color: #00ff88; }
.judgment-good { color: #f7c948; }
.judgment-miss { color: #ff006e; }
/* Countdown Overlay */
.countdown-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.9);
display: none;
align-items: center;
justify-content: center;
z-index: 200;
flex-direction: column;
gap: 20px;
}
.countdown-overlay.active {
display: flex;
}
.countdown-number {
font-family: 'Press Start 2P', cursive;
font-size: 8em;
color: var(--neon-cyan);
text-shadow: 0 0 50px var(--neon-cyan);
animation: countdownPulse 1s ease-in-out;
}
@keyframes countdownPulse {
0% { transform: scale(2); opacity: 0; }
50% { transform: scale(1); opacity: 1; }
100% { transform: scale(0.8); opacity: 0.5; }
}
.countdown-text {
font-family: 'Orbitron', sans-serif;
font-size: 1.5em;
color: rgba(255,255,255,0.6);
}
/* Results Screen */
.results-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.95);
display: none;
align-items: center;
justify-content: center;
z-index: 300;
}
.results-overlay.active {
display: flex;
}
.results-card {
background: linear-gradient(135deg, rgba(20,20,40,0.98), rgba(40,20,60,0.98));
border: 2px solid var(--neon-pink);
border-radius: 20px;
padding: 40px;
text-align: center;
max-width: 500px;
width: 90%;
}
.results-title {
font-family: 'Press Start 2P', cursive;
font-size: 1.5em;
margin-bottom: 10px;
background: linear-gradient(90deg, var(--neon-pink), var(--neon-cyan));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.results-song {
font-size: 1.2em;
color: rgba(255,255,255,0.8);
margin-bottom: 30px;
}
.results-stars {
font-size: 3em;
margin-bottom: 20px;
}
.results-stats {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
margin-bottom: 30px;
}
.result-stat {
background: rgba(0,0,0,0.3);
padding: 15px;
border-radius: 10px;
}
.result-stat-value {
font-family: 'Orbitron', sans-serif;
font-size: 1.8em;
font-weight: 700;
}
.result-stat-label {
font-size: 0.75em;
color: rgba(255,255,255,0.5);
}
.results-buttons {
display: flex;
gap: 15px;
justify-content: center;
}
.btn-result {
padding: 15px 30px;
border-radius: 10px;
font-weight: 700;
font-size: 1em;
cursor: pointer;
border: none;
transition: all 0.2s;
}
.btn-retry {
background: linear-gradient(135deg, var(--neon-green), #00aa55);
color: #000;
}
.btn-menu {
background: transparent;
border: 2px solid var(--neon-cyan);
color: var(--neon-cyan);
}
/* Explosion Effects Canvas */
#effectsCanvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 50;
}
/* Speed Control */
.speed-control {
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
background: rgba(0,0,0,0.3);
border-radius: 8px;
margin-top: 8px;
}
.speed-slider {
flex: 1;
-webkit-appearance: none;
height: 6px;
background: rgba(255,255,255,0.1);
border-radius: 3px;
}
.speed-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
background: var(--neon-cyan);
border-radius: 50%;
cursor: pointer;
}
.speed-value {
font-family: 'Orbitron', sans-serif;
font-size: 0.8em;
color: var(--neon-cyan);
min-width: 45px;
text-align: right;
}
/* Loading indicator */
.loading-indicator {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-family: 'Press Start 2P', cursive;
font-size: 0.8em;
color: var(--neon-cyan);
display: none;
}
.loading-indicator.active {
display: block;
animation: blink 1s infinite;
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
</style>
</head>
<body>
<div class="game-container">
<!-- Header -->
<div class="header">
<div class="logo">ROCK BAND - SONG MODE</div>
<div class="header-stats">
<div class="header-stat">
<div class="header-stat-value" id="headerScore">0</div>
<div class="header-stat-label">Score</div>
</div>
<div class="header-stat">
<div class="header-stat-value" id="headerStreak">0</div>
<div class="header-stat-label">Streak</div>
</div>
<div class="multiplier" id="multiplierDisplay">1x</div>
</div>
</div>
<!-- Left Panel - Song Selection -->
<div class="song-panel">
<div class="panel-title">Load Song</div>
<!-- YouTube Input -->
<div class="youtube-section">
<div class="youtube-input-group">
<input type="text" class="youtube-input" id="youtubeUrl"
placeholder="Paste YouTube URL...">
<button class="btn btn-youtube" onclick="loadYouTubeVideo()">
Load Video
</button>
</div>
<div class="bpm-controls">
<span class="bpm-label">BPM:</span>
<input type="number" class="bpm-input" id="bpmInput" value="120" min="60" max="300">
<button class="btn btn-tap" onclick="startTapTempo()">TAP TEMPO</button>
</div>
<div class="speed-control">
<span class="bpm-label">Speed:</span>
<input type="range" class="speed-slider" id="speedSlider" min="25" max="100" value="100">
<span class="speed-value" id="speedValue">100%</span>
</div>
</div>
<div class="panel-title" style="margin-top: 15px;">Song Library</div>
<!-- Song Library -->
<div class="song-library" id="songLibrary">
<!-- Songs populated by JS -->
</div>
</div>
<!-- Main Game Area -->
<div class="game-area">
<!-- Video Container -->
<div class="video-container">
<div id="youtube-player"></div>
<div class="video-overlay"></div>
<div class="video-info">
<div class="now-playing">
<div class="now-playing-title" id="nowPlayingTitle">No Song Loaded</div>
<div class="now-playing-artist" id="nowPlayingArtist">Load a YouTube video to begin</div>
</div>
<div class="video-time" id="videoTime">0:00 / 0:00</div>
</div>
<div class="loading-indicator" id="loadingIndicator">LOADING...</div>
</div>
<!-- Note Highway -->
<div class="highway-container">
<canvas id="noteHighway"></canvas>
<!-- Hit Zone -->
<div class="hit-zone-container">
<div class="hit-zone">
<div class="drum-lane" data-drum="kick" data-note="36">
<span class="key-hint">SPACE</span>
</div>
<div class="drum-lane" data-drum="snare" data-note="38">
<span class="key-hint">S</span>
</div>
<div class="drum-lane" data-drum="hihat" data-note="46">
<span class="key-hint">H</span>
</div>
<div class="drum-lane" data-drum="crash" data-note="49">
<span class="key-hint">C</span>
</div>
<div class="drum-lane" data-drum="tom1" data-note="48">
<span class="key-hint">T</span>
</div>
<div class="drum-lane" data-drum="tom2" data-note="45">
<span class="key-hint">Y</span>
</div>
<div class="drum-lane" data-drum="ride" data-note="51">
<span class="key-hint">R</span>
</div>
</div>
</div>
</div>
</div>
<!-- Right Panel - Stats -->
<div class="stats-panel">
<!-- Star Power -->
<div class="star-power-section">
<div class="star-power-header">
<span class="star-power-title">STAR POWER</span>
<span class="star-power-status" id="starPowerStatus">CHARGING</span>
</div>
<div class="star-power-bar">
<div class="star-power-fill" id="starPowerFill"></div>
</div>
</div>
<!-- Crowd Meter -->
<div class="crowd-section">
<div class="crowd-header">
<span class="crowd-title">Crowd</span>
<span class="crowd-reaction" id="crowdReaction">Ready</span>
</div>
<div class="crowd-bar">
<div class="crowd-fill" id="crowdFill" style="background: linear-gradient(90deg, #f7c948, #00ff88);"></div>
</div>
</div>
<!-- Score -->
<div class="score-section">
<div class="score-label">Total Score</div>
<div class="score-value" id="scoreDisplay">0</div>
</div>
<!-- Combo & Stats -->
<div class="combo-section">
<div class="stat-box">
<div class="stat-box-value combo-value" id="comboDisplay">0</div>
<div class="stat-box-label">Combo</div>
</div>
<div class="stat-box">
<div class="stat-box-value streak-value" id="maxStreakDisplay">0</div>
<div class="stat-box-label">Max Streak</div>
</div>
<div class="stat-box">
<div class="stat-box-value accuracy-value" id="accuracyDisplay">100%</div>
<div class="stat-box-label">Accuracy</div>
</div>
<div class="stat-box">
<div class="stat-box-value notes-value" id="notesHitDisplay">0/0</div>
<div class="stat-box-label">Notes Hit</div>
</div>
</div>
<!-- SEFERIM Panel -->
<div class="seferim-section">
<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 Phi</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="seferimLevel">1</div>
<div class="seferim-stat-label">Level</div>
</div>
</div>
<div class="seferim-families" id="seferimFamilies"></div>
</div>
<!-- Controls -->
<div class="controls-section">
<button class="btn btn-control btn-start" id="startBtn" onclick="startGame()">
START
</button>
<div class="practice-toggle">
<span>Practice Mode (No Fail)</span>
<div class="toggle-switch" id="practiceToggle" onclick="togglePractice()"></div>
</div>
</div>
</div>
</div>
<!-- Judgment Display -->
<div class="judgment-display" id="judgmentDisplay"></div>
<!-- Countdown Overlay -->
<div class="countdown-overlay" id="countdownOverlay">
<div class="countdown-number" id="countdownNumber">3</div>
<div class="countdown-text" id="countdownText">Get Ready!</div>
</div>
<!-- Results Overlay -->
<div class="results-overlay" id="resultsOverlay">
<div class="results-card">
<div class="results-title">SONG COMPLETE!</div>
<div class="results-song" id="resultsSong">Song Name</div>
<div class="results-stars" id="resultsStars"></div>
<div class="results-stats">
<div class="result-stat">
<div class="result-stat-value" id="resultScore" style="color: var(--neon-cyan);">0</div>
<div class="result-stat-label">Final Score</div>
</div>
<div class="result-stat">
<div class="result-stat-value" id="resultAccuracy" style="color: var(--neon-green);">0%</div>
<div class="result-stat-label">Accuracy</div>
</div>
<div class="result-stat">
<div class="result-stat-value" id="resultStreak" style="color: var(--snare-color);">0</div>
<div class="result-stat-label">Max Streak</div>
</div>
<div class="result-stat">
<div class="result-stat-value" id="resultNotes" style="color: var(--neon-pink);">0/0</div>
<div class="result-stat-label">Notes Hit</div>
</div>
</div>
<div class="results-buttons">
<button class="btn-result btn-retry" onclick="restartSong()">PLAY AGAIN</button>
<button class="btn-result btn-menu" onclick="backToMenu()">SONG LIST</button>
</div>
</div>
</div>
<!-- Effects Canvas -->
<canvas id="effectsCanvas"></canvas>
<!-- YouTube API -->
<script src="https://www.youtube.com/iframe_api"></script>
<script>
// ═══════════════════════════════════════════════════════════════════════════
// GAME CONFIGURATION
// ═══════════════════════════════════════════════════════════════════════════
const DRUMS = ['kick', 'snare', 'hihat', 'crash', 'tom1', 'tom2', 'ride'];
const DRUM_COLORS = {
kick: '#ff6b35',
snare: '#f7c948',
hihat: '#4ecdc4',
crash: '#ff006e',
tom1: '#8338ec',
tom2: '#3a86ff',
ride: '#06ffa5'
};
const DRUM_MIDI_MAP = {
36: 'kick', 38: 'snare', 46: 'hihat',
49: 'crash', 48: 'tom1', 45: 'tom2', 51: 'ride'
};
const KEY_MAP = {
' ': 'kick', 's': 'snare', 'h': 'hihat',
'c': 'crash', 't': 'tom1', 'y': 'tom2', 'r': 'ride'
};
// Timing windows (ms)
const TIMING = {
perfect: 40,
great: 80,
good: 120,
miss: 180
};
// ═══════════════════════════════════════════════════════════════════════════
// SONG DATABASE WITH YOUTUBE PATTERNS
// ═══════════════════════════════════════════════════════════════════════════
const SONG_DATABASE = [
{
id: 'seven-nation-army',
title: 'Seven Nation Army',
artist: 'The White Stripes',
youtubeId: '0J2QdDbelmY',
bpm: 124,
difficulty: 'easy',
offset: 0,
// Pattern format: [time_in_ms, drum_type]
generatePattern: function(duration) {
const pattern = [];
const beatMs = 60000 / this.bpm;
let time = beatMs * 4; // Start after 4 beats
while (time < duration) {
// Basic rock beat
pattern.push([time, 'kick']);
pattern.push([time, 'hihat']);
pattern.push([time + beatMs, 'hihat']);
pattern.push([time + beatMs * 2, 'snare']);
pattern.push([time + beatMs * 2, 'hihat']);
pattern.push([time + beatMs * 3, 'hihat']);
time += beatMs * 4;
}
return pattern;
}
},
{
id: 'billie-jean',
title: 'Billie Jean',
artist: 'Michael Jackson',
youtubeId: 'Zi_XLOBDo_Y',
bpm: 117,
difficulty: 'medium',
offset: 500,
generatePattern: function(duration) {
const pattern = [];
const beatMs = 60000 / this.bpm;
let time = beatMs * 4;
while (time < duration) {
// Disco beat
pattern.push([time, 'kick']);
pattern.push([time, 'hihat']);
pattern.push([time + beatMs * 0.5, 'hihat']);
pattern.push([time + beatMs, 'hihat']);
pattern.push([time + beatMs * 1.5, 'hihat']);
pattern.push([time + beatMs * 2, 'snare']);
pattern.push([time + beatMs * 2, 'kick']);
pattern.push([time + beatMs * 2, 'hihat']);
pattern.push([time + beatMs * 2.5, 'hihat']);
pattern.push([time + beatMs * 3, 'hihat']);
pattern.push([time + beatMs * 3.5, 'hihat']);
time += beatMs * 4;
}
return pattern;
}
},
{
id: 'smells-like-teen-spirit',
title: 'Smells Like Teen Spirit',
artist: 'Nirvana',
youtubeId: 'hTWKbfoikeg',
bpm: 117,
difficulty: 'medium',
offset: 200,
generatePattern: function(duration) {
const pattern = [];
const beatMs = 60000 / this.bpm;
let time = beatMs * 8;
while (time < duration) {
// Grunge beat
pattern.push([time, 'crash']);
pattern.push([time, 'kick']);
pattern.push([time + beatMs, 'hihat']);
pattern.push([time + beatMs * 1.5, 'kick']);
pattern.push([time + beatMs * 2, 'snare']);
pattern.push([time + beatMs * 2, 'hihat']);
pattern.push([time + beatMs * 3, 'hihat']);
pattern.push([time + beatMs * 3.5, 'kick']);
time += beatMs * 4;
}
return pattern;
}
},
{
id: 'back-in-black',
title: 'Back In Black',
artist: 'AC/DC',
youtubeId: 'pAgnJDJN4VA',
bpm: 92,
difficulty: 'medium',
offset: 3000,
generatePattern: function(duration) {
const pattern = [];
const beatMs = 60000 / this.bpm;
let time = beatMs * 8;
while (time < duration) {
pattern.push([time, 'crash']);
pattern.push([time, 'kick']);
pattern.push([time + beatMs * 2, 'snare']);
pattern.push([time + beatMs * 2, 'kick']);
pattern.push([time + beatMs * 4, 'kick']);
pattern.push([time + beatMs * 6, 'snare']);
pattern.push([time + beatMs * 6, 'kick']);
// Hi-hats
for (let i = 0; i < 8; i++) {
pattern.push([time + beatMs * i, 'hihat']);
}
time += beatMs * 8;
}
return pattern;
}
},
{
id: 'enter-sandman',
title: 'Enter Sandman',
artist: 'Metallica',
youtubeId: 'CD-E-LDc384',
bpm: 123,
difficulty: 'hard',
offset: 1000,
generatePattern: function(duration) {
const pattern = [];
const beatMs = 60000 / this.bpm;
let time = beatMs * 16;
while (time < duration) {
// Heavy metal beat
pattern.push([time, 'crash']);
pattern.push([time, 'kick']);
pattern.push([time + beatMs * 0.5, 'kick']);
pattern.push([time + beatMs, 'hihat']);
pattern.push([time + beatMs * 1.5, 'kick']);
pattern.push([time + beatMs * 2, 'snare']);
pattern.push([time + beatMs * 2, 'kick']);
pattern.push([time + beatMs * 2.5, 'kick']);
pattern.push([time + beatMs * 3, 'hihat']);
pattern.push([time + beatMs * 3.5, 'kick']);
time += beatMs * 4;
}
return pattern;
}
},
{
id: 'uptown-funk',
title: 'Uptown Funk',
artist: 'Bruno Mars',
youtubeId: 'OPf0YbXqDm0',
bpm: 115,
difficulty: 'medium',
offset: 1500,
generatePattern: function(duration) {
const pattern = [];
const beatMs = 60000 / this.bpm;
let time = beatMs * 8;
while (time < duration) {
// Funk beat
pattern.push([time, 'kick']);
pattern.push([time + beatMs * 0.75, 'kick']);
pattern.push([time + beatMs * 2, 'snare']);
pattern.push([time + beatMs * 2.75, 'kick']);
// Hi-hat pattern
for (let i = 0; i < 4; i++) {
pattern.push([time + beatMs * i, 'hihat']);
pattern.push([time + beatMs * (i + 0.5), 'hihat']);
}
time += beatMs * 4;
}
return pattern;
}
},
{
id: 'blinding-lights',
title: 'Blinding Lights',
artist: 'The Weeknd',
youtubeId: '4NRXx6U8ABQ',
bpm: 171,
difficulty: 'hard',
offset: 500,
generatePattern: function(duration) {
const pattern = [];
const beatMs = 60000 / this.bpm;
let time = beatMs * 8;
while (time < duration) {
// 80s synth pop beat
pattern.push([time, 'kick']);
pattern.push([time + beatMs, 'snare']);
pattern.push([time + beatMs * 2, 'kick']);
pattern.push([time + beatMs * 3, 'snare']);
// Fast hi-hats
for (let i = 0; i < 4; i++) {
pattern.push([time + beatMs * i, 'hihat']);
pattern.push([time + beatMs * (i + 0.5), 'hihat']);
}
time += beatMs * 4;
}
return pattern;
}
},
{
id: 'come-as-you-are',
title: 'Come As You Are',
artist: 'Nirvana',
youtubeId: 'vabnZ9-ex7o',
bpm: 120,
difficulty: 'easy',
offset: 2000,
generatePattern: function(duration) {
const pattern = [];
const beatMs = 60000 / this.bpm;
let time = beatMs * 8;