Code edit (1 edits merged)
Please save this source code
User prompt
update with: // Reduce spawn ahead time even more var NOTE_SPAWN_AHEAD_MS = 400; // Reduced from 800ms to 400ms // Fix the tap feedback positioning in game.down function game.down = function (x, y, obj) { if (playerHealth <= 0 || !gameStartTime) { return; } var currentTime = Date.now() - gameStartTime; // Show tap feedback AT THE TAP LOCATION, not on scanner var feedback = game.attachAsset('tapFeedback', { anchorX: 0.5, anchorY: 0.5 }); feedback.x = x; feedback.y = y; // Changed from scanner.y to actual tap y position feedback.alpha = 0.7; tween(feedback, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 300, onFinish: function onFinish() { if (feedback && feedback.destroy) { feedback.destroy(); } } }); // Rest of the hit detection code stays the same... var hitOccurred = false; var tapRadius = 100; for (var i = notes.length - 1; i >= 0; i--) { var note = notes[i]; if (!note || !note.active || note.isHit || note.isSpawning) { continue; } // Check distance from tap var dx = x - note.x; var dy = y - note.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < tapRadius) { // Check timing - note should be near scanner var scannerDiff = Math.abs(scanner.y - note.y); if (scannerDiff < HIT_TOLERANCE_PX) { note.isHit = true; note.showHitEffect(); var timeDiff = Math.abs(currentTime - note.hitTime); var points = 10; if (timeDiff < 50) points = 20; // Perfect hit else if (timeDiff < 100) points = 15; // Great hit LK.setScore(LK.getScore() + points); scoreTxt.setText(LK.getScore()); hitOccurred = true; if (LK.getScore() >= TARGET_SCORE_TO_WIN) { LK.showYouWin(); gameStartTime = null; tween.stop(scanner); return; } break; } } } }; // Also improve the spawn timing logic function spawnNotesForCurrentTime(currentTime) { if (!currentSongData) { return; } currentSongData.notes.forEach(function (noteData, index) { var noteKey = index + '_' + noteData.time; if (spawnedNotes.indexOf(noteKey) === -1) { var timeUntilHit = noteData.time - currentTime; // More precise spawning - only spawn when really needed if (timeUntilHit <= NOTE_SPAWN_AHEAD_MS && timeUntilHit > -200) { if (!noteData.color) { noteData.color = NOTE_COLORS[Math.floor(Math.random() * NOTE_COLORS.length)]; } var properY = calculateNoteYFromTime(noteData.time, currentTime); var correctedNoteData = { time: noteData.time, type: noteData.type, x: noteData.x, y: properY, color: noteData.color, duration: noteData.duration, path: noteData.path }; var note = new Note(correctedNoteData, currentTime); notes.push(note); game.addChild(note); note.spawnIn(); spawnedNotes.push(noteKey); } } }); } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
update with: // Game Constants (update these) var NOTE_SPAWN_AHEAD_MS = 800; // Reduce from 2000 to 800ms - notes appear closer to hit time var SCANNER_CYCLE_DURATION = 4000; // 4 seconds total cycle var SCANNER_HALF_CYCLE = SCANNER_CYCLE_DURATION / 2; // 2 seconds each direction // Modified spawnNotesForCurrentTime function function spawnNotesForCurrentTime(currentTime) { if (!currentSongData) { return; } currentSongData.notes.forEach(function (noteData, index) { var noteKey = index + '_' + noteData.time; // Only spawn if not already spawned and within spawn window if (spawnedNotes.indexOf(noteKey) === -1) { // Calculate when this note should spawn based on scanner position var timeUntilHit = noteData.time - currentTime; // Spawn note when scanner is approaching (not all at once) if (timeUntilHit <= NOTE_SPAWN_AHEAD_MS && timeUntilHit > -500) { // Assign random color if not specified if (!noteData.color) { noteData.color = NOTE_COLORS[Math.floor(Math.random() * NOTE_COLORS.length)]; } // Calculate proper Y position based on scanner cycle var properY = calculateNoteYFromTime(noteData.time, currentTime); // Override the Y position with calculated value var correctedNoteData = { time: noteData.time, type: noteData.type, x: noteData.x, y: properY, // Use calculated Y position color: noteData.color, duration: noteData.duration, path: noteData.path }; var note = new Note(correctedNoteData, currentTime); notes.push(note); game.addChild(note); note.spawnIn(); spawnedNotes.push(noteKey); } } }); } // Fixed calculateNoteYFromTime function function calculateNoteYFromTime(noteTime, currentTime) { // Determine where in the scanner cycle this note should be hit var cycleTime = noteTime % SCANNER_CYCLE_DURATION; if (cycleTime < SCANNER_HALF_CYCLE) { // First half of cycle: scanner moving down var progressInPhase = cycleTime / SCANNER_HALF_CYCLE; return SCANNER_Y_MIN + (progressInPhase * PLAY_AREA_HEIGHT); } else { // Second half of cycle: scanner moving up var progressInPhase = (cycleTime - SCANNER_HALF_CYCLE) / SCANNER_HALF_CYCLE; return SCANNER_Y_MAX - (progressInPhase * PLAY_AREA_HEIGHT); } } // Update the default song data with better timing spread var defaultSongData = { bpm: 120, scannerCycleDuration: 4000, notes: [ // First cycle (0-4000ms) - spread across scanner movement { time: 500, type: 'tap', x: 500, y: 0 }, // Early in down movement { time: 1200, type: 'tap', x: 800, y: 0 }, // Mid down movement { time: 2000, type: 'tap', x: 1200, y: 0 }, // Bottom turn { time: 2800, type: 'hold', x: 600, y: 0, duration: 500 }, // Mid up movement { time: 3500, type: 'tap', x: 900, y: 0 }, // Near top // Second cycle (4000-8000ms) { time: 4500, type: 'tap', x: 400, y: 0 }, { time: 5200, type: 'drag', x: 1000, y: 0, path: [{ x: 1200, y: 0 }] }, { time: 6000, type: 'tap', x: 700, y: 0 }, { time: 6800, type: 'hold', x: 800, y: 0, duration: 400 }, { time: 7500, type: 'tap', x: 500, y: 0 }, // Third cycle (8000-12000ms) { time: 8500, type: 'tap', x: 600, y: 0 }, { time: 9200, type: 'tap', x: 1100, y: 0 }, { time: 10000, type: 'drag', x: 400, y: 0, path: [{ x: 600, y: 0 }] }, { time: 10800, type: 'tap', x: 900, y: 0 }, { time: 11500, type: 'tap', x: 800, y: 0 } ] };
User prompt
the scanline should start at the bottom and move upwards
User prompt
Please fix the bug: 'TypeError: self.createHoldTrail is not a function' in or related to this line: 'self.createHoldTrail();' Line Number: 68
User prompt
Please fix the bug: 'Set is not a constructor' in or related to this line: 'var spawnedNotes = new Set(); // Track which notes have been spawned' Line Number: 216
Code edit (1 edits merged)
Please save this source code
User prompt
Do not remove player health if enemy hit is succrssful.
User prompt
Do not spawn enemies at the very top and bottom 10%.
User prompt
Please fix the bug: 'LK.gui.add is not a function. (In 'LK.gui.add(pip)', 'LK.gui.add' is undefined)' in or related to this line: 'LK.gui.add(pip); // Add to general GUI layer' Line Number: 327
Code edit (1 edits merged)
Please save this source code
User prompt
Rhythm Lane Defender
Initial prompt
**RHYTHM TOWER DEFENSE PROTOTYPE - GAME DESIGN SPECIFICATION** Create a single-screen rhythm tower defense game with these specifications: **Core Layout:** - 3 vertical lanes of equal width spanning the screen - Horizontal timing bar that spans full screen width - Timing bar continuously travels up and down the screen in smooth, deliberate motion - Enemies spawn as stationary objects positioned throughout the lane areas **Game Mechanics:** - Timing bar completes one full up-down cycle over 8 beats at 100-110 BPM (slower, more strategic pace) - Enemies appear as stationary targets in lanes, aligned to beat timing - **Maximum 2 enemies can share the same horizontal position (row) across all lanes** - respecting two-thumb input limitation - Different enemy patterns can appear on upstroke vs downstroke passes - Player presses lane key when timing bar intersects stationary enemy AND on the beat - Successful hits destroy enemies with visual destruction effect - Score system tracks successful hits with end-game rating **Enemy System:** - Simple colored shapes positioned at various heights within lanes - Spawn timing aligned to beat structure with strategic positioning - Stationary once spawned - timing bar does the moving - Visual destruction effect when successfully eliminated - Spawn logic ensures never more than 2 enemies at same horizontal level **Controls & Feedback:** - 3 lane input keys (suggest A, S, D) - Visual feedback for key presses - Clear indication when timing bar aligns with enemies - Beat-synchronized visual cues throughout game **UI Elements:** - Score display - Health indicator (reduced when enemies are missed) - Lane key indicators at bottom - End-game rating system based on performance **Technical Focus:** - Smooth timing bar animation at deliberate pace (8-beat cycles) - Precise hit detection when bar intersects stationary enemies on beat - Enemy spawn system that respects 2-enemy-per-row maximum - Clean visual feedback for successful hits and misses
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var BackgroundParticle = Container.expand(function () { var self = Container.call(this); self.particleGraphics = null; self.baseSpeed = 0; self.initialScale = 1; self.baseAlpha = 0.1; self._startTwinkleAnimation = function () { tween.stop(self, { alpha: true }); var currentAlpha = self.alpha; var pulseDelta = self.baseAlpha * 0.4; var targetMinAlpha = Math.max(0.05, self.baseAlpha - pulseDelta); var targetMaxAlpha = Math.min(1.0, self.baseAlpha + pulseDelta); if (targetMaxAlpha - targetMinAlpha < 0.05) { if (self.baseAlpha < 0.15) { targetMaxAlpha = Math.min(1.0, self.baseAlpha + 0.1); } else if (self.baseAlpha > 0.85) { targetMinAlpha = Math.max(0.05, self.baseAlpha - 0.1); } if (targetMaxAlpha - targetMinAlpha < 0.05) { return; } } var nextTargetAlpha; if (self.alpha === self.baseAlpha || Math.abs(currentAlpha - targetMaxAlpha) < Math.abs(currentAlpha - targetMinAlpha)) { nextTargetAlpha = targetMinAlpha; } else { nextTargetAlpha = targetMaxAlpha; } var pulseDuration = 300 + Math.random() * 400; tween(self, { alpha: nextTargetAlpha }, { duration: pulseDuration, easing: tween.easeInOut, onFinish: function onFinish() { if (self && self._startTwinkleAnimation) { self._startTwinkleAnimation(); } } }); }; self.init = function () { tween.stop(self, { alpha: true }); var scale = 0.312 + Math.random() * 1.248; self.initialScale = scale; self.scale.set(scale); var colors = [0xff00ff, 0x00ffff, 0xffff00, 0xff0000, 0x00ff00, 0x0000ff, 0xffa500, 0xda70d6]; var color = colors[Math.floor(Math.random() * colors.length)]; if (self.particleGraphics) { self.particleGraphics.destroy(); } self.particleGraphics = self.attachAsset('starParticle', { anchorX: 0.5, anchorY: 0.5 }); self.particleGraphics.tint = color; self.baseSpeed = (0.5 + Math.random() * 1.5) * scale; // Distribute particles evenly across the screen self.x = Math.random() * GAME_WIDTH; self.y = Math.random() * GAME_HEIGHT; // Start particles throughout the screen self.baseAlpha = 0.1 + Math.random() * 0.7; self.alpha = self.baseAlpha; self._startTwinkleAnimation(); }; self.updateParticle = function () { // Get current direction (smoothly interpolated if changing) var currentDirection = getCurrentParticleDirection(); // Calculate total speed (base * game speed * countdown acceleration) var totalSpeed = self.baseSpeed * baseParticleSpeed * (isCountdownActive ? countdownAcceleration : 1); // Move in the current direction - simple linear movement self.x += currentDirection.x * totalSpeed; self.y += currentDirection.y * totalSpeed; // Reset particle if it goes off screen - improved distribution logic var margin = 100; if (self.x < -margin || self.x > GAME_WIDTH + margin || self.y < -margin || self.y > GAME_HEIGHT + margin) { // Use weighted probability to spawn on different edges // 60% opposite edge, 40% distributed across other edges var spawnChoice = Math.random(); if (spawnChoice < 0.6) { // 60% - Spawn on opposite edge (current behavior) if (Math.abs(currentDirection.x) > Math.abs(currentDirection.y)) { if (currentDirection.x > 0) { self.x = -margin + Math.random() * 50; self.y = Math.random() * GAME_HEIGHT; } else { self.x = GAME_WIDTH + margin - Math.random() * 50; self.y = Math.random() * GAME_HEIGHT; } } else { if (currentDirection.y > 0) { self.x = Math.random() * GAME_WIDTH; self.y = -margin + Math.random() * 50; } else { self.x = Math.random() * GAME_WIDTH; self.y = GAME_HEIGHT + margin - Math.random() * 50; } } } else { // 40% - Spawn randomly on any edge for better distribution var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top edge self.x = Math.random() * GAME_WIDTH; self.y = -margin + Math.random() * 50; break; case 1: // Right edge self.x = GAME_WIDTH + margin - Math.random() * 50; self.y = Math.random() * GAME_HEIGHT; break; case 2: // Bottom edge self.x = Math.random() * GAME_WIDTH; self.y = GAME_HEIGHT + margin - Math.random() * 50; break; case 3: // Left edge self.x = -margin + Math.random() * 50; self.y = Math.random() * GAME_HEIGHT; break; } } } }; self.init(); return self; }); var Note = Container.expand(function (noteData, spawnTime) { var self = Container.call(this); self.noteData = noteData; self.type = noteData.type; self.targetX = noteData.x; self.targetY = noteData.y; self.hitTime = noteData.time; self.duration = noteData.duration || 0; self.spawnTime = spawnTime; self.zone = noteData.x < GAME_WIDTH / 2 ? 'left' : 'right'; if (noteData.color && noteData.color === SYNC_NOTE_COLOR) { if (self.type === 'tap') { self.color = COLOR_SYNC_TAP; } else if (self.type === 'hold') { self.color = COLOR_SYNC_HOLD; } else { self.color = self.zone === 'left' ? COLOR_LEFT_ZONE : COLOR_RIGHT_ZONE; } } else { self.color = self.zone === 'left' ? COLOR_LEFT_ZONE : COLOR_RIGHT_ZONE; } self.active = true; self.isHit = false; self.isMissed = false; self.isSpawning = true; self.isHolding = false; self.holdSuccessfullyCompleted = false; self.holdParticles = []; self.lastParticleEmissionTime = 0; self.PARTICLE_EMISSION_INTERVAL = 50; self.holdStarted = false; self.beatPulseInterval = null; var assetName = self.type === 'hold' ? 'holdNoteCore' : 'noteCore'; self.noteGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.noteGraphics.tint = self.color; self._startBeatPulseAnimation = function () { if (!self || !self.active || self.isHit || self.isMissed || self.isSpawning) { tween.stop(self, { scaleX: true, scaleY: true }); return; } tween.stop(self, { scaleX: true, scaleY: true }); tween(self, { scaleX: 1.15, scaleY: 1.15 }, { duration: BEAT_DURATION_MS * 0.2, easing: tween.easeOut, onFinish: function onFinish() { if (self && self.active && !self.isHit && !self.isMissed && !self.isSpawning) { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: BEAT_DURATION_MS * 0.2, easing: tween.easeIn }); } } }); }; self._clearBeatPulseLoop = function () { if (self.beatPulseInterval) { LK.clearInterval(self.beatPulseInterval); self.beatPulseInterval = null; } tween.stop(self, { scaleX: true, scaleY: true }); }; self._initiateBeatPulseLoop = function () { self._clearBeatPulseLoop(); if (self && self.active && !self.isHit && !self.isMissed && !self.isSpawning) { self._startBeatPulseAnimation(); self.beatPulseInterval = LK.setInterval(function () { if (self && self.active && !self.isHit && !self.isMissed && !self.isSpawning) { self._startBeatPulseAnimation(); } else { self._clearBeatPulseLoop(); } }, BEAT_DURATION_MS); } }; self.x = self.targetX; self.y = self.targetY; self.alpha = 0; self.scaleX = 0.1; self.scaleY = 0.1; self.createHoldTrail = function () { var cycleTime = self.hitTime % SCANNER_CYCLE_DURATION; var scannerMovingUp = cycleTime < SCANNER_HALF_CYCLE; var direction = scannerMovingUp ? -1 : 1; var originalRequestedDuration = self.duration; var maxPossibleTrailPixelLength = originalRequestedDuration / SCANNER_HALF_CYCLE * PLAY_AREA_HEIGHT; var actualTrailPixelLength = maxPossibleTrailPixelLength; if (direction === -1) { if (self.y - actualTrailPixelLength < SCANNER_Y_MIN) { actualTrailPixelLength = self.y - SCANNER_Y_MIN; } } else { if (self.y + actualTrailPixelLength > SCANNER_Y_MAX) { actualTrailPixelLength = SCANNER_Y_MAX - self.y; } } actualTrailPixelLength = Math.max(0, actualTrailPixelLength); if (actualTrailPixelLength < maxPossibleTrailPixelLength) { if (PLAY_AREA_HEIGHT > 0 && SCANNER_HALF_CYCLE > 0) { self.duration = actualTrailPixelLength / PLAY_AREA_HEIGHT * SCANNER_HALF_CYCLE; } else if (actualTrailPixelLength === 0) { self.duration = 0; } } self.duration = Math.max(0, self.duration); // Create trail line first so it's below everything else var trailLine = self.attachAsset('holdTrail', { anchorX: 0.5, anchorY: 0 }); trailLine.tint = self.color; trailLine.alpha = 0.6; trailLine.height = actualTrailPixelLength; if (direction === -1) { trailLine.y = -actualTrailPixelLength; } else { trailLine.y = 0; } self.holdTrails.push(trailLine); // Move the trail to index 0 so it's below the note graphics self.setChildIndex(trailLine, 0); self.endNote = self.attachAsset('noteCore', { anchorX: 0.5, anchorY: 0.5 }); self.endNote.tint = self.color; self.endNote.alpha = 0.8; self.endNote.scaleX = 0.7; self.endNote.scaleY = 0.7; self.endNote.y = actualTrailPixelLength * direction; self.endGlow = self.attachAsset('glowRing', { anchorX: 0.5, anchorY: 0.5 }); self.endGlow.tint = self.color; self.endGlow.alpha = 0.3; self.endGlow.scaleX = 0.5; self.endGlow.scaleY = 0.5; self.endGlow.y = actualTrailPixelLength * direction; }; self.holdTrails = []; if (self.type === 'hold' && self.duration > 0) { self.createHoldTrail(); } self.spawnIn = function () { self.isSpawning = true; tween(self, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 400, // Increased duration for better elastic effect easing: tween.easeElasticOut, // Changed to elastic easing for bouncy appearance onFinish: function onFinish() { self.isSpawning = false; self._initiateBeatPulseLoop(); } }); }; self.showHitEffect = function () { self._clearBeatPulseLoop(); LK.getSound('hitSound').play(); self.explodeIntoParticles(); tween(self, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, onFinish: function onFinish() { self.active = false; self._clearBeatPulseLoop(); } }); }; self.startHoldEffect = function () { self._clearBeatPulseLoop(); LK.getSound('hitSound').play(); tween(self.noteGraphics, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, onFinish: function onFinish() { tween(self.noteGraphics, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); }; self.showMissEffect = function () { self._clearBeatPulseLoop(); LK.getSound('missSound').play(); // First change color to red tween(self.noteGraphics, { tint: 0xff0000 }, { duration: 150, onFinish: function onFinish() { // Then collapse inward with elastic ease-in for a crushing effect tween(self, { alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 500, // Slightly longer for dramatic effect easing: tween.easeElasticIn, // Elastic ease-in for collapsing effect onFinish: function onFinish() { self.active = false; self._clearBeatPulseLoop(); } }); } }); }; self.explodeIntoParticles = function () { var noteScale = 1.2; // Base scale relative to noteCore (300px) // Stage 1: Initial Flash (0-200ms) var flash = game.attachAsset('supernovaFlash', { anchorX: 0.5, anchorY: 0.5 }); flash.tint = 0xFFFFFF; flash.x = self.x; flash.y = self.y; flash.alpha = 0; flash.scale.set(0.1 * noteScale); tween(flash, { alpha: 1, scaleX: 2.8 * noteScale, scaleY: 2.8 * noteScale }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { tween(flash, { alpha: 0 }, { duration: 350, onFinish: function onFinish() { if (flash && flash.destroy) { flash.destroy(); } } }); } }); // Stage 2: Shockwave (100-600ms) LK.setTimeout(function () { var shockwave = game.attachAsset('supernovaShockwave', { anchorX: 0.5, anchorY: 0.5 }); shockwave.tint = 0x00FFFF; shockwave.x = self.x; shockwave.y = self.y; shockwave.alpha = 1; shockwave.scale.set(0.2 * noteScale); tween(shockwave, { scaleX: 5.0 * noteScale, scaleY: 5.0 * noteScale, alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { if (shockwave && shockwave.destroy) { shockwave.destroy(); } } }); }, 100); // Stage 3: Core Particles (50-800ms) var coreParticleCount = 15; for (var i = 0; i < coreParticleCount; i++) { (function (index) { LK.setTimeout(function () { var coreAsset = Math.random() < 0.5 ? 'supernovaCoreParticle' : 'supernovaCoreParticle2'; var particle = game.attachAsset(coreAsset, { anchorX: 0.5, anchorY: 0.5 }); particle.tint = Math.random() < 0.5 ? 0xFFFFFF : 0xFFFF88; particle.x = self.x; particle.y = self.y; var angle = index / coreParticleCount * Math.PI * 2 + (Math.random() - 0.5) * 0.5; var speed = 200 + Math.random() * 150; var targetX = self.x + Math.cos(angle) * speed; var targetY = self.y + Math.sin(angle) * speed; var finalScale = (0.5 + Math.random() * 0.4) * noteScale; particle.scale.set(0.2 * noteScale); tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: finalScale, scaleY: finalScale }, { duration: 900, easing: tween.easeOut, onFinish: function onFinish() { if (particle && particle.destroy) { particle.destroy(); } } }); }, 50 + Math.random() * 100); })(i); } // Stage 4: Nebula Trails (200-1200ms) var nebulaCount = 20; for (var j = 0; j < nebulaCount; j++) { (function (index) { LK.setTimeout(function () { var nebulaAssets = ['supernovaNebulaTrail', 'supernovaNebulaTrail2', 'supernovaNebulaTrail3']; var nebulaAsset = nebulaAssets[Math.floor(Math.random() * nebulaAssets.length)]; var particle = game.attachAsset(nebulaAsset, { anchorX: 0.5, anchorY: 0.5 }); var colors = [0x8844FF, 0xFF44AA, 0x4488FF, 0xAA44FF]; particle.tint = colors[Math.floor(Math.random() * colors.length)]; particle.x = self.x + (Math.random() - 0.5) * 40; particle.y = self.y + (Math.random() - 0.5) * 40; particle.alpha = 0.8 + Math.random() * 0.3; var angle = Math.random() * Math.PI * 2; var speed = 80 + Math.random() * 120; var targetX = self.x + Math.cos(angle) * speed; var targetY = self.y + Math.sin(angle) * speed; var finalScale = (0.4 + Math.random() * 0.3) * noteScale; particle.scale.set(0.2 * noteScale); tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: finalScale, scaleY: finalScale, rotation: Math.random() * Math.PI * 2 }, { duration: 1300, easing: tween.easeOut, onFinish: function onFinish() { if (particle && particle.destroy) { particle.destroy(); } } }); }, 200 + Math.random() * 200); })(j); } // Stage 5: Stellar Debris (150-1000ms) var debrisCount = 12; for (var k = 0; k < debrisCount; k++) { (function (index) { LK.setTimeout(function () { var debrisAsset = Math.random() < 0.5 ? 'supernovaStellarDebris' : 'supernovaStellarDebris2'; var particle = game.attachAsset(debrisAsset, { anchorX: 0.5, anchorY: 0.5 }); var colors = [0xFF4400, 0xFF6600, 0xFFAA00, 0xFFFFFF]; particle.tint = colors[Math.floor(Math.random() * colors.length)]; particle.x = self.x; particle.y = self.y; var angle = Math.random() * Math.PI * 2; var speed = 120 + Math.random() * 100; var targetX = self.x + Math.cos(angle) * speed; var targetY = self.y + Math.sin(angle) * speed; var finalScale = (0.25 + Math.random() * 0.25) * noteScale; particle.scale.set(0.10 * noteScale); tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: finalScale, scaleY: finalScale, rotation: Math.random() * Math.PI * 4 // Multiple rotations }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { if (particle && particle.destroy) { particle.destroy(); } } }); }, 150 + Math.random() * 150); })(k); } // Stage 6: Energy Sparks (100-700ms) var sparkCount = 25; for (var l = 0; l < sparkCount; l++) { (function (index) { LK.setTimeout(function () { var sparkAsset = Math.random() < 0.5 ? 'supernovaEnergySpark' : 'supernovaEnergySpark2'; var particle = game.attachAsset(sparkAsset, { anchorX: 0.5, anchorY: 0.5 }); particle.tint = Math.random() < 0.5 ? 0x00FFFF : 0x0088FF; particle.x = self.x + (Math.random() - 0.5) * 20; particle.y = self.y + (Math.random() - 0.5) * 20; var angle = Math.random() * Math.PI * 2; var speed = 180 + Math.random() * 220; var targetX = self.x + Math.cos(angle) * speed; var targetY = self.y + Math.sin(angle) * speed; var finalScale = (0.2 + Math.random() * 0.2) * noteScale; particle.scale.set(0.1 * noteScale); tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: finalScale, scaleY: finalScale }, { duration: 900, easing: tween.easeOut, onFinish: function onFinish() { if (particle && particle.destroy) { particle.destroy(); } } }); }, 100 + Math.random() * 100); })(l); } // Stage 7: Afterglow (300-1500ms) LK.setTimeout(function () { var afterglow = game.attachAsset('supernovaAfterglow', { anchorX: 0.5, anchorY: 0.5 }); afterglow.tint = 0xFF6600; afterglow.x = self.x; afterglow.y = self.y; afterglow.alpha = 0.4; afterglow.scale.set(1.2 * noteScale); tween(afterglow, { alpha: 0, scaleX: 3.0 * noteScale, scaleY: 3.0 * noteScale }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { if (afterglow && afterglow.destroy) { afterglow.destroy(); } } }); }, 400); }; self.explodeEndNoteParticles = function () { if (!self.endNote) { return; } var noteScale = 1.2; // Same scale as main note var endNoteGlobalX = self.x; var endNoteGlobalY = self.y + self.endNote.y; // Stage 1: Initial Flash (0-200ms) var flash = game.attachAsset('supernovaFlash', { anchorX: 0.5, anchorY: 0.5 }); flash.tint = 0xFFFFFF; flash.x = endNoteGlobalX; flash.y = endNoteGlobalY; flash.alpha = 0; flash.scale.set(0.1 * noteScale); tween(flash, { alpha: 1, scaleX: 2.5 * noteScale, scaleY: 2.5 * noteScale }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(flash, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { if (flash && flash.destroy) { flash.destroy(); } } }); } }); // Stage 2: Shockwave (100-600ms) LK.setTimeout(function () { var shockwave = game.attachAsset('supernovaShockwave', { anchorX: 0.5, anchorY: 0.5 }); shockwave.tint = 0x00FFFF; shockwave.x = endNoteGlobalX; shockwave.y = endNoteGlobalY; shockwave.alpha = 0.9; shockwave.scale.set(0.2 * noteScale); tween(shockwave, { scaleX: 5.0 * noteScale, scaleY: 5.0 * noteScale, alpha: 0 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { if (shockwave && shockwave.destroy) { shockwave.destroy(); } } }); }, 100); // Stage 3: Core Particles (50-800ms) var coreParticleCount = 15; for (var i = 0; i < coreParticleCount; i++) { (function (index) { LK.setTimeout(function () { var coreAsset = Math.random() < 0.5 ? 'supernovaCoreParticle' : 'supernovaCoreParticle2'; var particle = game.attachAsset(coreAsset, { anchorX: 0.5, anchorY: 0.5 }); particle.tint = Math.random() < 0.5 ? 0xFFFFFF : 0xFFFF88; particle.x = endNoteGlobalX; particle.y = endNoteGlobalY; var angle = index / coreParticleCount * Math.PI * 2 + (Math.random() - 0.5) * 0.5; var speed = 200 + Math.random() * 150; var targetX = endNoteGlobalX + Math.cos(angle) * speed; var targetY = endNoteGlobalY + Math.sin(angle) * speed; var finalScale = (0.3 + Math.random() * 0.4) * noteScale; particle.scale.set(0.1 * noteScale); tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: finalScale, scaleY: finalScale }, { duration: 750, easing: tween.easeOut, onFinish: function onFinish() { if (particle && particle.destroy) { particle.destroy(); } } }); }, 50 + Math.random() * 100); })(i); } // Stage 4: Nebula Trails (200-1200ms) var nebulaCount = 20; for (var j = 0; j < nebulaCount; j++) { (function (index) { LK.setTimeout(function () { var nebulaAssets = ['supernovaNebulaTrail', 'supernovaNebulaTrail2', 'supernovaNebulaTrail3']; var nebulaAsset = nebulaAssets[Math.floor(Math.random() * nebulaAssets.length)]; var particle = game.attachAsset(nebulaAsset, { anchorX: 0.5, anchorY: 0.5 }); var colors = [0x8844FF, 0xFF44AA, 0x4488FF, 0xAA44FF]; particle.tint = colors[Math.floor(Math.random() * colors.length)]; particle.x = endNoteGlobalX + (Math.random() - 0.5) * 40; particle.y = endNoteGlobalY + (Math.random() - 0.5) * 40; particle.alpha = 0.7 + Math.random() * 0.3; var angle = Math.random() * Math.PI * 2; var speed = 80 + Math.random() * 120; var targetX = endNoteGlobalX + Math.cos(angle) * speed; var targetY = endNoteGlobalY + Math.sin(angle) * speed; var finalScale = (0.2 + Math.random() * 0.3) * noteScale; particle.scale.set(0.1 * noteScale); tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: finalScale, scaleY: finalScale, rotation: Math.random() * Math.PI * 2 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { if (particle && particle.destroy) { particle.destroy(); } } }); }, 200 + Math.random() * 200); })(j); } // Stage 5: Stellar Debris (150-1000ms) var debrisCount = 12; for (var k = 0; k < debrisCount; k++) { (function (index) { LK.setTimeout(function () { var debrisAsset = Math.random() < 0.5 ? 'supernovaStellarDebris' : 'supernovaStellarDebris2'; var particle = game.attachAsset(debrisAsset, { anchorX: 0.5, anchorY: 0.5 }); var colors = [0xFF4400, 0xFF6600, 0xFFAA00, 0xFFFFFF]; particle.tint = colors[Math.floor(Math.random() * colors.length)]; particle.x = endNoteGlobalX; particle.y = endNoteGlobalY; var angle = Math.random() * Math.PI * 2; var speed = 120 + Math.random() * 100; var targetX = endNoteGlobalX + Math.cos(angle) * speed; var targetY = endNoteGlobalY + Math.sin(angle) * speed; var finalScale = (0.15 + Math.random() * 0.25) * noteScale; particle.scale.set(0.05 * noteScale); tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: finalScale, scaleY: finalScale, rotation: Math.random() * Math.PI * 4 }, { duration: 850, easing: tween.easeOut, onFinish: function onFinish() { if (particle && particle.destroy) { particle.destroy(); } } }); }, 150 + Math.random() * 150); })(k); } // Stage 6: Energy Sparks (100-700ms) var sparkCount = 25; for (var l = 0; l < sparkCount; l++) { (function (index) { LK.setTimeout(function () { var sparkAsset = Math.random() < 0.5 ? 'supernovaEnergySpark' : 'supernovaEnergySpark2'; var particle = game.attachAsset(sparkAsset, { anchorX: 0.5, anchorY: 0.5 }); particle.tint = Math.random() < 0.5 ? 0x00FFFF : 0x0088FF; particle.x = endNoteGlobalX + (Math.random() - 0.5) * 20; particle.y = endNoteGlobalY + (Math.random() - 0.5) * 20; var angle = Math.random() * Math.PI * 2; var speed = 180 + Math.random() * 220; var targetX = endNoteGlobalX + Math.cos(angle) * speed; var targetY = endNoteGlobalY + Math.sin(angle) * speed; var finalScale = (0.1 + Math.random() * 0.2) * noteScale; particle.scale.set(0.05 * noteScale); tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: finalScale, scaleY: finalScale }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { if (particle && particle.destroy) { particle.destroy(); } } }); }, 100 + Math.random() * 100); })(l); } // Stage 7: Afterglow (300-1500ms) LK.setTimeout(function () { var afterglow = game.attachAsset('supernovaAfterglow', { anchorX: 0.5, anchorY: 0.5 }); afterglow.tint = 0xFF6600; afterglow.x = endNoteGlobalX; afterglow.y = endNoteGlobalY; afterglow.alpha = 0.4; afterglow.scale.set(1.2 * noteScale); tween(afterglow, { alpha: 0, scaleX: 2.0 * noteScale, scaleY: 2.0 * noteScale }, { duration: 1200, easing: tween.easeOut, onFinish: function onFinish() { if (afterglow && afterglow.destroy) { afterglow.destroy(); } } }); }, 300); }; self.updateHoldEffects = function (scannerCurrentY) { if (self.type === 'hold' && self.isHolding && self.active && !self.holdSuccessfullyCompleted && !self.isMissed) { var currentTime = Date.now(); if (currentTime - self.lastParticleEmissionTime > self.PARTICLE_EMISSION_INTERVAL) { self.lastParticleEmissionTime = currentTime; var trailStartY = self.y; var trailEndY = self.y + (self.endNote ? self.endNote.y : 0); var scannerIsOverTrail = self.endNote && scannerCurrentY >= Math.min(trailStartY, trailEndY) && scannerCurrentY <= Math.max(trailStartY, trailEndY); if (scannerIsOverTrail) { var particle = game.attachAsset('holdConnectionParticle', { anchorX: 0.5, anchorY: 0.5 }); particle.x = self.x; particle.y = scannerCurrentY; particle.tint = self.color; particle.alpha = 0.8; self.holdParticles.push(particle); tween(particle, { alpha: 0, scaleX: 0.2, scaleY: 0.2 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { if (particle && particle.destroy) { particle.destroy(); } var index = self.holdParticles.indexOf(particle); if (index > -1) { self.holdParticles.splice(index, 1); } } }); } } } }; self.cleanupHoldVisuals = function () { self.holdParticles.forEach(function (p) { if (p && p.destroy) { p.destroy(); } }); self.holdParticles = []; if (self.endNote && self.endNote.destroy) { self.endNote.destroy(); } if (self.endGlow && self.endGlow.destroy) { self.endGlow.destroy(); } self.endNote = null; self.endGlow = null; self.holdTrails.forEach(function (trail) { if (trail && trail.destroy) { trail.destroy(); } }); self.holdTrails = []; }; self.completeHold = function () { if (self.holdSuccessfullyCompleted || self.isMissed) { return; } self._clearBeatPulseLoop(); self.holdSuccessfullyCompleted = true; self.isHolding = false; self.explodeIntoParticles(); if (self.type === 'hold') { self.explodeEndNoteParticles(); } self.cleanupHoldVisuals(); tween(self, { alpha: 0 }, { duration: 100, delay: 100, onFinish: function onFinish() { self.active = false; self._clearBeatPulseLoop(); } }); }; self.failHold = function () { if (self.isMissed || self.holdSuccessfullyCompleted) { return; } self._clearBeatPulseLoop(); self.isMissed = true; self.isHolding = false; self.showMissEffect(); self.cleanupHoldVisuals(); }; return self; }); var Scanner = Container.expand(function () { var self = Container.call(this); self.glow = self.attachAsset('scannerGlow', { anchorX: 0, anchorY: 0.5 }); self.glow.alpha = 0.2; self.line = self.attachAsset('scannerLine', { anchorX: 0, anchorY: 0.5 }); self.x = 0; self.isMovingUp = true; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Add these global variables (replace the previous ones) var globalParticleDirection = { x: 0, y: 1 }; // Start moving downward var targetParticleDirection = { x: 0, y: 1 }; var directionChangeStartTime = 0; var directionChangeDuration = 1000; // 1 second var isChangingDirection = false; var lastDirectionChangeTime = 0; var nextDirectionChangeDelay = 15000 + Math.random() * 15000; // 15-30 seconds var baseParticleSpeed = 1; // Base speed multiplier var countdownAcceleration = 1; // Separate from base speed var isCountdownActive = false; var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var SAFETY_MARGIN_TOP_PERCENT = 0.05; var SAFETY_MARGIN_BOTTOM_PERCENT = 0.15; var SAFETY_MARGIN_SIDES_PERCENT = 0.10; var BPM = 120; var BEAT_DURATION_MS = 60 / BPM * 1000; var SCANNER_Y_MIN = GAME_HEIGHT * SAFETY_MARGIN_TOP_PERCENT; var SCANNER_Y_MAX = GAME_HEIGHT * (1 - SAFETY_MARGIN_BOTTOM_PERCENT); var PLAY_AREA_HEIGHT = SCANNER_Y_MAX - SCANNER_Y_MIN; var NOTE_SPAWN_AHEAD_MS = 800; var PERFECT_HIT_RATIO = 0.4; var POINTS_PERFECT_TAP = 30; var POINTS_GOOD_TAP = 15; var POINTS_PERFECT_HOLD_START = 10; var POINTS_GOOD_HOLD_START = 5; var ACCURACY_POPUP_DURATION = 750; var ACCURACY_POPUP_Y_OFFSET = -100; var ACCURACY_POPUP_FONT_SIZE = 80; var PERFECT_POPUP_COLOR = 0x00FF00; var GOOD_POPUP_COLOR = 0xFFFF00; var SCANNER_CYCLE_DURATION = 4000; var SCANNER_HALF_CYCLE = SCANNER_CYCLE_DURATION / 2; var HIT_TOLERANCE_PX_FOR_HOLD_END = 100; var HOLD_END_GRACE_PERIOD_MS = 250; var GAME_STATE_TITLE = 'title'; var GAME_STATE_SONG_SELECT = 'songSelect'; var GAME_STATE_PLAYING = 'playing'; var GAME_STATE_RESULTS = 'results'; var GAME_STATE_TUTORIAL = 'tutorial'; // New game state for the tutorial var currentGameState = GAME_STATE_TITLE; var resultsScreen = {}; var tutorialScreen = {}; // Holds tutorial screen elements var activeHoldNotes = {}; var scoreTxt; var countdownTxt; var perfectCount = 0; var goodCount = 0; var missCount = 0; var scanner; var scannerIsMovingUp = true; var gameStartTime; var gameStarted = false; var notes = []; var currentSongData; var spawnedNotes = []; var leftZone, rightZone; var isDragging = false; var dragStartX, dragStartY; var currentTrail = []; var backgroundParticles = []; var NUM_BACKGROUND_PARTICLES = 200; var titleScreen = {}; var songSelectScreen = {}; var songSelectScrollY = 0; var maxScrollY = 0; var isDraggingSongList = false; var dragStartYSongList = 0; var songSelectionInProgress = false; // Flag to prevent multiple song selections simultaneously var SONG_ITEM_HEIGHT = 330; var COLOR_LEFT_ZONE = 0x0077FF; var COLOR_RIGHT_ZONE = 0xFF3333; var COLOR_SYNC_TAP = 0xFF69B4; var COLOR_SYNC_HOLD = 0x9370DB; var SYNC_NOTE_COLOR = 0xFFA500; // Helper function to get current particle direction with smooth interpolation function getCurrentParticleDirection() { if (!isChangingDirection) { return globalParticleDirection; } var currentTime = Date.now(); var elapsed = currentTime - directionChangeStartTime; var progress = Math.min(elapsed / directionChangeDuration, 1); // Smooth easing var easedProgress = progress * progress * (3 - 2 * progress); // Smoothstep // Interpolate between current and target direction var lerpX = globalParticleDirection.x + (targetParticleDirection.x - globalParticleDirection.x) * easedProgress; var lerpY = globalParticleDirection.y + (targetParticleDirection.y - globalParticleDirection.y) * easedProgress; // Normalize the direction var length = Math.sqrt(lerpX * lerpX + lerpY * lerpY); if (length > 0) { lerpX /= length; lerpY /= length; } // Check if transition is complete if (progress >= 1) { isChangingDirection = false; globalParticleDirection.x = targetParticleDirection.x; globalParticleDirection.y = targetParticleDirection.y; lastDirectionChangeTime = currentTime; nextDirectionChangeDelay = 15000 + Math.random() * 15000; // 15-30 seconds } return { x: lerpX, y: lerpY }; } // Function to initiate a direction change function changeParticleDirection() { if (isChangingDirection) { return; } // Calculate the turn direction var currentAngle = Math.atan2(globalParticleDirection.y, globalParticleDirection.x); var angleChange = Math.PI / 4 + Math.random() * (Math.PI / 4); // 45-90 degrees if (Math.random() < 0.5) { angleChange = -angleChange; } var newAngle = currentAngle + angleChange; targetParticleDirection.x = Math.cos(newAngle); targetParticleDirection.y = Math.sin(newAngle); // Predict which corner will become bare and pre-fill it // var turnDirection = angleChange; // Positive = turning counter-clockwise, Negative = turning clockwise // Not directly used but good for understanding // Determine which corner will be "left behind" by the turn var bareCornerX, bareCornerY; // var currentDir = globalParticleDirection; // Not strictly needed as newDir determines flow out var newDir = targetParticleDirection; // The bare corner is opposite to where particles are flowing towards *after* the turn. // Example: If newDir is bottom-right (x > 0, y > 0), particles flow towards bottom-right. // The corner "emptied" or "left behind" will be the top-left (0,0). if (newDir.x > 0 && newDir.y > 0) { // Flowing toward bottom-right bareCornerX = 0; // Top-left will be bare bareCornerY = 0; } else if (newDir.x < 0 && newDir.y > 0) { // Flowing toward bottom-left bareCornerX = GAME_WIDTH; // Top-right will be bare bareCornerY = 0; } else if (newDir.x < 0 && newDir.y < 0) { // Flowing toward top-left bareCornerX = GAME_WIDTH; // Bottom-right will be bare bareCornerY = GAME_HEIGHT; } else { // Flowing toward top-right (newDir.x > 0 && newDir.y < 0) bareCornerX = 0; // Bottom-left will be bare bareCornerY = GAME_HEIGHT; } // Spawn particles in the predicted bare corner area var cornerSize = Math.min(GAME_WIDTH, GAME_HEIGHT) * 0.3; // 30% of screen from corner for (var i = 0; i < 15; i++) { var extraParticle = new BackgroundParticle(); // Position in the bare corner area if (bareCornerX === 0) { extraParticle.x = Math.random() * cornerSize; } else { extraParticle.x = GAME_WIDTH - Math.random() * cornerSize; } if (bareCornerY === 0) { extraParticle.y = Math.random() * cornerSize; } else { extraParticle.y = GAME_HEIGHT - Math.random() * cornerSize; } backgroundParticles.push(extraParticle); game.addChildAt(extraParticle, 0); // Add behind other game elements } isChangingDirection = true; directionChangeStartTime = Date.now(); } var PatternTemplates = { tapLeft: function tapLeft(startTime) { return [{ time: startTime, type: 'tap', zone: 'left' }]; }, tapRight: function tapRight(startTime) { return [{ time: startTime, type: 'tap', zone: 'right' }]; }, syncTap: function syncTap(startTime) { return [{ time: startTime, type: 'tap', zone: 'left' }, { time: startTime, type: 'tap', zone: 'right' }]; }, leftRightTaps: function leftRightTaps(startTime, spacing) { spacing = spacing || 500; return [{ time: startTime, type: 'tap', zone: 'left' }, { time: startTime + spacing, type: 'tap', zone: 'right' }]; }, rightLeftTaps: function rightLeftTaps(startTime, spacing) { spacing = spacing || 500; return [{ time: startTime, type: 'tap', zone: 'right' }, { time: startTime + spacing, type: 'tap', zone: 'left' }]; }, holdLeft: function holdLeft(startTime, duration) { duration = duration || 1000; return [{ time: startTime, type: 'hold', zone: 'left', duration: duration }]; }, holdRight: function holdRight(startTime, duration) { duration = duration || 1000; return [{ time: startTime, type: 'hold', zone: 'right', duration: duration }]; }, syncHold: function syncHold(startTime, duration) { duration = duration || 1000; return [{ time: startTime, type: 'hold', zone: 'left', duration: duration }, { time: startTime, type: 'hold', zone: 'right', duration: duration }]; }, tripletTaps: function tripletTaps(startTime, zone, spacing) { spacing = spacing || 167; return [{ time: startTime, type: 'tap', zone: zone }, { time: startTime + spacing, type: 'tap', zone: zone }, { time: startTime + spacing * 2, type: 'tap', zone: zone }]; }, alternatingTriplets: function alternatingTriplets(startTime, spacing) { spacing = spacing || 167; return [{ time: startTime, type: 'tap', zone: 'left' }, { time: startTime + spacing, type: 'tap', zone: 'right' }, { time: startTime + spacing * 2, type: 'tap', zone: 'left' }]; }, buildUp: function buildUp(startTime) { return [{ time: startTime, type: 'tap', zone: 'left' }, { time: startTime + 250, type: 'tap', zone: 'right' }, { time: startTime + 500, type: 'tap', zone: 'left' }, { time: startTime + 625, type: 'tap', zone: 'right' }, { time: startTime + 750, type: 'tap', zone: 'left' }, { time: startTime + 875, type: 'tap', zone: 'right' }]; } }; var SongGenerator = { generateSong: function generateSong(config) { var notes = []; var totalLength = config.totalLength || 202136; var startTime = config.startDelay || 2000; notes = this.generateZoneAwareSong(startTime, totalLength); notes.sort(function (a, b) { return a.time - b.time; }); return notes; }, generateZoneAwareSong: function generateZoneAwareSong(startTime, songTotalLength) { var notes = []; var currentTime = startTime; var zoneFreeTime = { left: startTime, right: startTime }; var MIN_SAME_ZONE_SPACING = 400; var MIN_DIFFERENT_ZONE_SPACING = 200; var MIN_SYNC_SPACING = 1000; var lastSyncTime = startTime - MIN_SYNC_SPACING; var sections = [{ start: 0, end: 16000, complexity: 'simple' }, { start: 16000, end: 48000, complexity: 'medium' }, { start: 48000, end: 72000, complexity: 'medium' }, { start: 72000, end: 104000, complexity: 'medium' }, { start: 104000, end: 128000, complexity: 'complex' }, { start: 128000, end: 160000, complexity: 'medium' }, { start: 160000, end: 184000, complexity: 'complex' }, { start: 184000, end: songTotalLength, complexity: 'simple' }]; for (var s = 0; s < sections.length; s++) { var section = sections[s]; var sectionStartTime = startTime + section.start; var sectionEndTime = startTime + section.end; if (sectionEndTime > startTime + songTotalLength) { sectionEndTime = startTime + songTotalLength; } if (sectionStartTime >= sectionEndTime) { continue; } currentTime = Math.max(currentTime, sectionStartTime); while (currentTime < sectionEndTime - 1000) { var pattern = this.selectPattern(section.complexity, zoneFreeTime, currentTime, lastSyncTime); var patternResult = this.placePattern(pattern, currentTime, zoneFreeTime, MIN_SAME_ZONE_SPACING, MIN_DIFFERENT_ZONE_SPACING, sectionEndTime); if (patternResult.notes.length > 0) { var allNotesFit = true; for (var ni = 0; ni < patternResult.notes.length; ni++) { if (patternResult.notes[ni].time + (patternResult.notes[ni].duration || 0) > sectionEndTime - 200) { allNotesFit = false; break; } } if (allNotesFit) { notes = notes.concat(patternResult.notes); currentTime = patternResult.nextTime; if (pattern.type === 'sync' || pattern.type === 'syncHold') { lastSyncTime = patternResult.notes[0].time; } } else { currentTime += 300; } } else { currentTime += 300; } if (currentTime >= sectionEndTime - 1000) { break; } } } return notes; }, selectPattern: function selectPattern(complexity, zoneFreeTime, currentTime, lastSyncTime) { var patterns = []; var MIN_SYNC_SPACING_FOR_SELECTION = 1000; if (complexity === 'simple') { patterns = [{ type: 'single', zone: 'left', duration: 800 }, { type: 'single', zone: 'right', duration: 800 }, { type: 'rest', duration: 1200 }, { type: 'rest', duration: 1200 }]; if (currentTime - lastSyncTime >= MIN_SYNC_SPACING_FOR_SELECTION + 200) { patterns.push({ type: 'sync', duration: 1000 }); } } else if (complexity === 'medium') { patterns = [{ type: 'hold', zone: 'right', holdDuration: 1000, duration: 700 }, { type: 'single', zone: 'left', duration: 600 }, { type: 'single', zone: 'right', duration: 600 }, { type: 'single', zone: 'left', duration: 600 }, { type: 'single', zone: 'right', duration: 600 }, { type: 'alternating', duration: 750 }, { type: 'rest', duration: 1000 }]; if (currentTime - lastSyncTime >= MIN_SYNC_SPACING_FOR_SELECTION) { patterns.push({ type: 'sync', duration: 800 }); patterns.push({ type: 'sync', duration: 800 }); } } else { patterns = [{ type: 'hold', zone: 'right', holdDuration: 1200, duration: 800 }, { type: 'alternating', duration: 800 }, { type: 'alternating', duration: 800 }, { type: 'single', zone: 'left', duration: 700 }, { type: 'single', zone: 'right', duration: 700 }, { type: 'single', zone: 'left', duration: 700 }, { type: 'single', zone: 'right', duration: 700 }]; if (currentTime - lastSyncTime >= MIN_SYNC_SPACING_FOR_SELECTION - 200) { patterns.push({ type: 'sync', duration: 600 }); patterns.push({ type: 'sync', duration: 600 }); patterns.push({ type: 'syncHold', holdDuration: 1200, duration: 900 }); } } return patterns[Math.floor(Math.random() * patterns.length)]; }, placePattern: function placePattern(pattern, requestedTime, zoneFreeTime, minSameZoneSpacing, minDiffZoneSpacing, sectionEndTime) { var notes = []; var earliestTime = requestedTime; var nextTimeAdvance = pattern.duration || 500; if (pattern.type === 'single') { earliestTime = Math.max(requestedTime, zoneFreeTime[pattern.zone]); if (earliestTime + (pattern.duration || 0) < sectionEndTime) { notes.push({ time: earliestTime, type: 'tap', zone: pattern.zone }); zoneFreeTime[pattern.zone] = earliestTime + minSameZoneSpacing; return { notes: notes, nextTime: earliestTime + nextTimeAdvance }; } } else if (pattern.type === 'sync') { earliestTime = Math.max(requestedTime, zoneFreeTime.left, zoneFreeTime.right); if (earliestTime + (pattern.duration || 0) < sectionEndTime) { notes.push({ time: earliestTime, type: 'tap', zone: 'left', color: SYNC_NOTE_COLOR }); notes.push({ time: earliestTime, type: 'tap', zone: 'right', color: SYNC_NOTE_COLOR }); zoneFreeTime.left = earliestTime + minSameZoneSpacing; zoneFreeTime.right = earliestTime + minSameZoneSpacing; return { notes: notes, nextTime: earliestTime + nextTimeAdvance }; } } else if (pattern.type === 'alternating') { var firstZone = Math.random() < 0.5 ? 'left' : 'right'; var secondZone = firstZone === 'left' ? 'right' : 'left'; var t1 = Math.max(requestedTime, zoneFreeTime[firstZone]); var t2 = Math.max(t1 + minDiffZoneSpacing, zoneFreeTime[secondZone]); if (t2 + (pattern.duration || 0) - (t2 - t1) < sectionEndTime) { notes.push({ time: t1, type: 'tap', zone: firstZone }); notes.push({ time: t2, type: 'tap', zone: secondZone }); zoneFreeTime[firstZone] = t1 + minSameZoneSpacing; zoneFreeTime[secondZone] = t2 + minSameZoneSpacing; return { notes: notes, nextTime: t1 + nextTimeAdvance }; } } else if (pattern.type === 'syncHold') { earliestTime = Math.max(requestedTime, zoneFreeTime.left, zoneFreeTime.right); var holdDuration = pattern.holdDuration || 1200; if (earliestTime + holdDuration < sectionEndTime) { notes.push({ time: earliestTime, type: 'hold', zone: 'left', duration: holdDuration, color: SYNC_NOTE_COLOR }); notes.push({ time: earliestTime, type: 'hold', zone: 'right', duration: holdDuration, color: SYNC_NOTE_COLOR }); zoneFreeTime.left = earliestTime + holdDuration + 200; zoneFreeTime.right = earliestTime + holdDuration + 200; return { notes: notes, nextTime: earliestTime + (pattern.duration || 800) }; } } else if (pattern.type === 'hold') { earliestTime = Math.max(requestedTime, zoneFreeTime[pattern.zone]); var holdDuration = pattern.holdDuration || 1500; if (earliestTime + holdDuration < sectionEndTime) { notes.push({ time: earliestTime, type: 'hold', zone: pattern.zone, duration: holdDuration }); var otherZone = pattern.zone === 'left' ? 'right' : 'left'; zoneFreeTime[pattern.zone] = earliestTime + holdDuration + 200; zoneFreeTime[otherZone] = Math.max(zoneFreeTime[otherZone], earliestTime + holdDuration + minDiffZoneSpacing); return { notes: notes, nextTime: earliestTime + nextTimeAdvance }; } } else if (pattern.type === 'rest') { return { notes: [], nextTime: requestedTime + (pattern.duration || 500) }; } return { notes: [], nextTime: requestedTime + 100 }; } }; function _createTutorialText(text, size, yPos, parent, fill, align, customX) { var textObj = new Text2(text, { size: size, fill: fill || 0xFFFFFF, wordWrap: true, wordWrapWidth: GAME_WIDTH - 200, // 100px padding each side align: align || 'left' }); if (align === 'center') { textObj.anchor.set(0.5, 0); textObj.x = customX || GAME_WIDTH / 2; } else { // left align textObj.anchor.set(0, 0); textObj.x = customX || 100; } textObj.y = yPos; parent.addChild(textObj); return textObj; } function _createTutorialNoteVisual(assetId, color, xPos, yPos, scale, parent) { var noteVisual = LK.getAsset(assetId, { anchorX: 0.5, anchorY: 0.5, scaleX: scale || 0.35, scaleY: scale || 0.35 }); noteVisual.tint = color; noteVisual.x = xPos; noteVisual.y = yPos; parent.addChild(noteVisual); return noteVisual; } var SongDatabase = { 'Remember This': { bpm: 99, scannerCycleDuration: 4000, totalLength: 205078, highScore: storage.highScores && storage.highScores['Remember This'] || 0, highestGrade: storage.highestGrades && storage.highestGrades['Remember This'] || 'C', notes: [{ "time": 673, "type": "tap", "zone": "right" }, { "time": 1277, "type": "tap", "zone": "left" }, { "time": 2461, "type": "tap", "zone": "left" }, { "time": 3065, "type": "tap", "zone": "right" }, { "time": 4249, "type": "tap", "zone": "right" }, { "time": 4852, "type": "tap", "zone": "left" }, { "time": 6060, "type": "tap", "zone": "left" }, { "time": 6664, "type": "tap", "zone": "right" }, { "time": 7848, "type": "tap", "zone": "right" }, { "time": 8452, "type": "tap", "zone": "left" }, { "time": 9659, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 9659, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 10263, "type": "tap", "zone": "right" }, { "time": 10866, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 12654, "type": "tap", "zone": "right" }, { "time": 13258, "type": "tap", "zone": "left" }, { "time": 13862, "type": "tap", "zone": "right" }, { "time": 14466, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 14466, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 15046, "type": "tap", "zone": "right" }, { "time": 15650, "type": "tap", "zone": "left" }, { "time": 16253, "type": "tap", "zone": "right" }, { "time": 16857, "type": "tap", "zone": "left" }, { "time": 17257, "type": "tap", "zone": "right" }, { "time": 18065, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 19853, "type": "tap", "zone": "right" }, { "time": 20456, "type": "tap", "zone": "left" }, { "time": 21037, "type": "tap", "zone": "right" }, { "time": 21640, "type": "tap", "zone": "left" }, { "time": 22244, "type": "tap", "zone": "right" }, { "time": 22848, "type": "tap", "zone": "left" }, { "time": 24055, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 24055, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 24659, "type": "tap", "zone": "right" }, { "time": 25263, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 27051, "type": "tap", "zone": "right" }, { "time": 27631, "type": "tap", "zone": "left" }, { "time": 28258, "type": "tap", "zone": "right" }, { "time": 28862, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 28862, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 29466, "type": "tap", "zone": "right" }, { "time": 30046, "type": "tap", "zone": "left" }, { "time": 31254, "type": "tap", "zone": "left" }, { "time": 31857, "type": "tap", "zone": "right" }, { "time": 32461, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 34249, "type": "tap", "zone": "right" }, { "time": 34853, "type": "tap", "zone": "left" }, { "time": 35456, "type": "tap", "zone": "right" }, { "time": 36060, "type": "tap", "zone": "left" }, { "time": 36641, "type": "tap", "zone": "right" }, { "time": 37244, "type": "tap", "zone": "left" }, { "time": 37848, "type": "tap", "zone": "right" }, { "time": 38475, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 38475, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 39102, "type": "tap", "zone": "right" }, { "time": 39775, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 41076, "type": "tap", "zone": "left" }, { "time": 42353, "type": "tap", "zone": "left" }, { "time": 42956, "type": "tap", "zone": "right" }, { "time": 44141, "type": "tap", "zone": "right" }, { "time": 44721, "type": "tap", "zone": "left" }, { "time": 45325, "type": "tap", "zone": "right" }, { "time": 45882, "type": "tap", "zone": "left" }, { "time": 46439, "type": "tap", "zone": "right" }, { "time": 47531, "type": "tap", "zone": "right" }, { "time": 48065, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 48065, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 48645, "type": "tap", "zone": "right" }, { "time": 49249, "type": "tap", "zone": "left" }, { "time": 49853, "type": "tap", "zone": "right" }, { "time": 50456, "type": "tap", "zone": "left" }, { "time": 50856, "type": "tap", "zone": "right" }, { "time": 51664, "type": "tap", "zone": "left" }, { "time": 52244, "type": "tap", "zone": "right" }, { "time": 52848, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 52848, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 53452, "type": "tap", "zone": "right" }, { "time": 54056, "type": "tap", "zone": "left" }, { "time": 54659, "type": "tap", "zone": "right" }, { "time": 55240, "type": "tap", "zone": "left" }, { "time": 55640, "type": "tap", "zone": "right" }, { "time": 56447, "type": "tap", "zone": "left" }, { "time": 57051, "type": "tap", "zone": "right" }, { "time": 57655, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 57655, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 59443, "type": "tap", "zone": "right" }, { "time": 60046, "type": "tap", "zone": "left" }, { "time": 60446, "type": "tap", "zone": "right" }, { "time": 61254, "type": "tap", "zone": "left" }, { "time": 61857, "type": "tap", "zone": "right" }, { "time": 62461, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 62461, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 63065, "type": "tap", "zone": "right" }, { "time": 63645, "type": "tap", "zone": "left" }, { "time": 64249, "type": "tap", "zone": "right" }, { "time": 64853, "type": "tap", "zone": "left" }, { "time": 65457, "type": "tap", "zone": "right" }, { "time": 66060, "type": "tap", "zone": "left" }, { "time": 66664, "type": "tap", "zone": "right" }, { "time": 67244, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 67244, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 69056, "type": "tap", "zone": "right" }, { "time": 69659, "type": "tap", "zone": "left" }, { "time": 70263, "type": "tap", "zone": "right" }, { "time": 70867, "type": "tap", "zone": "left" }, { "time": 71447, "type": "tap", "zone": "right" }, { "time": 72051, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 72051, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 72655, "type": "tap", "zone": "right" }, { "time": 73258, "type": "tap", "zone": "left" }, { "time": 73862, "type": "tap", "zone": "right" }, { "time": 74466, "type": "tap", "zone": "left" }, { "time": 75046, "type": "tap", "zone": "right" }, { "time": 75650, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 76858, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 76858, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 78065, "type": "tap", "zone": "left" }, { "time": 78669, "type": "tap", "zone": "right" }, { "time": 79876, "type": "tap", "zone": "right" }, { "time": 80457, "type": "tap", "zone": "left" }, { "time": 81664, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 81664, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 82245, "type": "tap", "zone": "right" }, { "time": 82848, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 84056, "type": "tap", "zone": "left" }, { "time": 84636, "type": "tap", "zone": "right" }, { "time": 85240, "type": "tap", "zone": "left" }, { "time": 85844, "type": "tap", "zone": "right" }, { "time": 86447, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 86447, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 88259, "type": "tap", "zone": "right" }, { "time": 88862, "type": "tap", "zone": "left" }, { "time": 89443, "type": "tap", "zone": "right" }, { "time": 90046, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 91254, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 91254, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 91858, "type": "tap", "zone": "right" }, { "time": 92461, "type": "tap", "zone": "left" }, { "time": 93042, "type": "tap", "zone": "right" }, { "time": 93646, "type": "tap", "zone": "left" }, { "time": 94249, "type": "tap", "zone": "right" }, { "time": 94853, "type": "tap", "zone": "left" }, { "time": 95457, "type": "tap", "zone": "right" }, { "time": 96060, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 96060, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 96641, "type": "tap", "zone": "right" }, { "time": 97245, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 98452, "type": "tap", "zone": "left" }, { "time": 99056, "type": "tap", "zone": "right" }, { "time": 99660, "type": "tap", "zone": "left" }, { "time": 100240, "type": "tap", "zone": "right" }, { "time": 100844, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 100844, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 101447, "type": "tap", "zone": "right" }, { "time": 102028, "type": "tap", "zone": "left" }, { "time": 103235, "type": "tap", "zone": "left" }, { "time": 103862, "type": "tap", "zone": "right" }, { "time": 105116, "type": "tap", "zone": "right" }, { "time": 105743, "type": "tap", "zone": "left" }, { "time": 106881, "type": "tap", "zone": "left" }, { "time": 107461, "type": "tap", "zone": "right" }, { "time": 108042, "type": "tap", "zone": "left" }, { "time": 108646, "type": "tap", "zone": "right" }, { "time": 109249, "type": "tap", "zone": "left" }, { "time": 109853, "type": "tap", "zone": "right" }, { "time": 110457, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 110457, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 111061, "type": "tap", "zone": "right" }, { "time": 111664, "type": "tap", "zone": "left" }, { "time": 112245, "type": "tap", "zone": "right" }, { "time": 112848, "type": "tap", "zone": "left" }, { "time": 113248, "type": "tap", "zone": "right" }, { "time": 114056, "type": "tap", "zone": "left" }, { "time": 114660, "type": "tap", "zone": "right" }, { "time": 115263, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 115263, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 117051, "type": "tap", "zone": "right" }, { "time": 117655, "type": "tap", "zone": "left" }, { "time": 118055, "type": "tap", "zone": "right" }, { "time": 118862, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 120650, "type": "tap", "zone": "right" }, { "time": 121254, "type": "tap", "zone": "left" }, { "time": 121858, "type": "tap", "zone": "right" }, { "time": 122462, "type": "tap", "zone": "left" }, { "time": 122862, "type": "tap", "zone": "right" }, { "time": 123646, "type": "tap", "zone": "left" }, { "time": 124249, "type": "tap", "zone": "right" }, { "time": 124853, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 124853, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 125457, "type": "tap", "zone": "right" }, { "time": 126061, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 128452, "type": "tap", "zone": "left" }, { "time": 129056, "type": "tap", "zone": "right" }, { "time": 129660, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 129660, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 130263, "type": "tap", "zone": "right" }, { "time": 130867, "type": "tap", "zone": "left" }, { "time": 131448, "type": "tap", "zone": "right" }, { "time": 132051, "type": "tap", "zone": "left" }, { "time": 132451, "type": "tap", "zone": "right" }, { "time": 133259, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 134466, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 134466, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 136254, "type": "tap", "zone": "right" }, { "time": 136858, "type": "tap", "zone": "left" }, { "time": 137258, "type": "tap", "zone": "right" }, { "time": 138042, "type": "tap", "zone": "left" }, { "time": 138646, "type": "tap", "zone": "right" }, { "time": 139250, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 139250, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 139853, "type": "tap", "zone": "right" }, { "time": 140457, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 141664, "type": "tap", "zone": "left" }, { "time": 142245, "type": "tap", "zone": "right" }, { "time": 142849, "type": "tap", "zone": "left" }, { "time": 143452, "type": "tap", "zone": "right" }, { "time": 144056, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 144056, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 145844, "type": "tap", "zone": "right" }, { "time": 146448, "type": "tap", "zone": "left" }, { "time": 147051, "type": "tap", "zone": "right" }, { "time": 148259, "type": "tap", "zone": "right" }, { "time": 148839, "type": "tap", "zone": "left" }, { "time": 150070, "type": "tap", "zone": "left" }, { "time": 150697, "type": "tap", "zone": "right" }, { "time": 151904, "type": "tap", "zone": "right" }, { "time": 152462, "type": "tap", "zone": "left" }, { "time": 153669, "type": "tap", "zone": "left" }, { "time": 154273, "type": "tap", "zone": "right" }, { "time": 155480, "type": "tap", "zone": "right" }, { "time": 156084, "type": "tap", "zone": "left" }, { "time": 157268, "type": "tap", "zone": "left" }, { "time": 157872, "type": "tap", "zone": "right" }, { "time": 159056, "type": "tap", "zone": "right" }, { "time": 159613, "type": "tap", "zone": "left" }, { "time": 160264, "type": "tap", "zone": "right" }, { "time": 160867, "type": "tap", "zone": "left" }, { "time": 161448, "type": "tap", "zone": "right" }, { "time": 162052, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 163259, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 163259, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 163863, "type": "tap", "zone": "right" }, { "time": 164420, "type": "tap", "zone": "left" }, { "time": 164977, "type": "tap", "zone": "right" }, { "time": 165535, "type": "tap", "zone": "left" }, { "time": 166115, "type": "tap", "zone": "right" }, { "time": 166719, "type": "tap", "zone": "left" }, { "time": 167903, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 167903, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 168530, "type": "tap", "zone": "right" }, { "time": 169250, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 170457, "type": "tap", "zone": "left" }, { "time": 170857, "type": "tap", "zone": "right" }, { "time": 171665, "type": "tap", "zone": "left" }, { "time": 172245, "type": "tap", "zone": "right" }, { "time": 172849, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 172849, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 174660, "type": "tap", "zone": "right" }, { "time": 175264, "type": "tap", "zone": "left" }, { "time": 175664, "type": "tap", "zone": "right" }, { "time": 176448, "type": "tap", "zone": "left" }, { "time": 177052, "type": "tap", "zone": "right" }, { "time": 177655, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 177655, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 178259, "type": "tap", "zone": "right" }, { "time": 178863, "type": "tap", "zone": "left" }, { "time": 179443, "type": "tap", "zone": "right" }, { "time": 180047, "type": "tap", "zone": "left" }, { "time": 180447, "type": "tap", "zone": "right" }, { "time": 181254, "type": "tap", "zone": "left" }, { "time": 181858, "type": "tap", "zone": "right" }, { "time": 182532, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 182532, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 183205, "type": "tap", "zone": "right" }, { "time": 184528, "type": "tap", "zone": "right" }, { "time": 185155, "type": "tap", "zone": "left" }, { "time": 185555, "type": "tap", "zone": "right" }, { "time": 186363, "type": "tap", "zone": "left" }, { "time": 186967, "type": "tap", "zone": "right" }, { "time": 187547, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 187547, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 188151, "type": "tap", "zone": "right" }, { "time": 188755, "type": "tap", "zone": "left" }, { "time": 189358, "type": "tap", "zone": "right" }, { "time": 189962, "type": "tap", "zone": "left" }, { "time": 190566, "type": "tap", "zone": "right" }, { "time": 191146, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 192354, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 192354, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 192957, "type": "tap", "zone": "right" }, { "time": 193561, "type": "tap", "zone": "left" }, { "time": 194165, "type": "tap", "zone": "right" }, { "time": 194745, "type": "tap", "zone": "left" }, { "time": 195349, "type": "tap", "zone": "right" }, { "time": 195953, "type": "tap", "zone": "left" }, { "time": 196556, "type": "tap", "zone": "right" }, { "time": 197160, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 197160, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 197764, "type": "tap", "zone": "right" }, { "time": 198344, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 199552, "type": "tap", "zone": "left" }, { "time": 200156, "type": "tap", "zone": "right" }, { "time": 200759, "type": "tap", "zone": "left" }] }, 'Arcade Heart': { bpm: 95, scannerCycleDuration: 4000, totalLength: 192446, highScore: storage.highScores && storage.highScores['Arcade Heart'] || 0, highestGrade: storage.highestGrades && storage.highestGrades['Arcade Heart'] || 'C', notes: [{ "time": 1602, "type": "tap", "zone": "right" }, { "time": 2229, "type": "tap", "zone": "left" }, { "time": 3482, "type": "tap", "zone": "left" }, { "time": 4133, "type": "tap", "zone": "right" }, { "time": 5387, "type": "tap", "zone": "right" }, { "time": 6013, "type": "tap", "zone": "left" }, { "time": 7291, "type": "tap", "zone": "left" }, { "time": 7918, "type": "tap", "zone": "right" }, { "time": 9171, "type": "tap", "zone": "right" }, { "time": 9798, "type": "tap", "zone": "left" }, { "time": 11052, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 11052, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 11702, "type": "tap", "zone": "right" }, { "time": 12329, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 13583, "type": "tap", "zone": "left" }, { "time": 14210, "type": "tap", "zone": "right" }, { "time": 14837, "type": "tap", "zone": "left" }, { "time": 15487, "type": "tap", "zone": "right" }, { "time": 16114, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 16114, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 16741, "type": "tap", "zone": "right" }, { "time": 17368, "type": "tap", "zone": "left" }, { "time": 18018, "type": "tap", "zone": "right" }, { "time": 18622, "type": "tap", "zone": "left" }, { "time": 19272, "type": "tap", "zone": "right" }, { "time": 19899, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 21153, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 21153, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 21803, "type": "tap", "zone": "right" }, { "time": 22430, "type": "tap", "zone": "left" }, { "time": 23057, "type": "tap", "zone": "right" }, { "time": 23684, "type": "tap", "zone": "left" }, { "time": 24334, "type": "tap", "zone": "right" }, { "time": 24938, "type": "tap", "zone": "left" }, { "time": 25588, "type": "tap", "zone": "right" }, { "time": 26215, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 26215, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 26865, "type": "tap", "zone": "right" }, { "time": 27492, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 28746, "type": "tap", "zone": "left" }, { "time": 29373, "type": "tap", "zone": "right" }, { "time": 30000, "type": "tap", "zone": "left" }, { "time": 30650, "type": "tap", "zone": "right" }, { "time": 31277, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 31277, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 31904, "type": "tap", "zone": "right" }, { "time": 32531, "type": "tap", "zone": "left" }, { "time": 33181, "type": "tap", "zone": "right" }, { "time": 33808, "type": "tap", "zone": "left" }, { "time": 34435, "type": "tap", "zone": "right" }, { "time": 35062, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 36316, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 36316, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 36966, "type": "tap", "zone": "right" }, { "time": 37593, "type": "tap", "zone": "left" }, { "time": 38220, "type": "tap", "zone": "right" }, { "time": 38846, "type": "tap", "zone": "left" }, { "time": 39497, "type": "tap", "zone": "right" }, { "time": 40124, "type": "tap", "zone": "left" }, { "time": 40751, "type": "tap", "zone": "right" }, { "time": 41377, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 41377, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 43281, "type": "tap", "zone": "right" }, { "time": 43908, "type": "tap", "zone": "left" }, { "time": 44535, "type": "tap", "zone": "right" }, { "time": 45162, "type": "tap", "zone": "left" }, { "time": 45812, "type": "tap", "zone": "right" }, { "time": 46439, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 46439, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 47066, "type": "tap", "zone": "right" }, { "time": 47693, "type": "tap", "zone": "left" }, { "time": 48320, "type": "tap", "zone": "right" }, { "time": 48947, "type": "tap", "zone": "left" }, { "time": 49347, "type": "tap", "zone": "right" }, { "time": 50224, "type": "tap", "zone": "left" }, { "time": 50851, "type": "tap", "zone": "right" }, { "time": 51478, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 51478, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 53382, "type": "tap", "zone": "right" }, { "time": 54009, "type": "tap", "zone": "left" }, { "time": 54409, "type": "tap", "zone": "right" }, { "time": 55263, "type": "tap", "zone": "left" }, { "time": 55913, "type": "tap", "zone": "right" }, { "time": 56540, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 56540, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 57167, "type": "tap", "zone": "right" }, { "time": 57794, "type": "tap", "zone": "left" }, { "time": 58444, "type": "tap", "zone": "right" }, { "time": 59071, "type": "tap", "zone": "left" }, { "time": 59698, "type": "tap", "zone": "right" }, { "time": 60325, "type": "tap", "zone": "left" }, { "time": 60952, "type": "tap", "zone": "right" }, { "time": 61602, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 61602, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 62229, "type": "tap", "zone": "right" }, { "time": 62856, "type": "tap", "zone": "left" }, { "time": 63483, "type": "tap", "zone": "right" }, { "time": 64110, "type": "tap", "zone": "left" }, { "time": 64510, "type": "tap", "zone": "right" }, { "time": 65387, "type": "tap", "zone": "left" }, { "time": 66014, "type": "tap", "zone": "right" }, { "time": 66641, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 66641, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 67268, "type": "tap", "zone": "right" }, { "time": 67918, "type": "tap", "zone": "left" }, { "time": 68545, "type": "tap", "zone": "right" }, { "time": 69799, "type": "tap", "zone": "right" }, { "time": 70426, "type": "tap", "zone": "left" }, { "time": 71703, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 71703, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 72330, "type": "tap", "zone": "right" }, { "time": 72957, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 74210, "type": "tap", "zone": "left" }, { "time": 74837, "type": "tap", "zone": "right" }, { "time": 75488, "type": "tap", "zone": "left" }, { "time": 76115, "type": "tap", "zone": "right" }, { "time": 76741, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 76741, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 77392, "type": "tap", "zone": "right" }, { "time": 78019, "type": "tap", "zone": "left" }, { "time": 78645, "type": "tap", "zone": "right" }, { "time": 79272, "type": "tap", "zone": "left" }, { "time": 79899, "type": "tap", "zone": "right" }, { "time": 80526, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 81803, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 81803, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 82430, "type": "tap", "zone": "right" }, { "time": 83057, "type": "tap", "zone": "left" }, { "time": 83684, "type": "tap", "zone": "right" }, { "time": 84311, "type": "tap", "zone": "left" }, { "time": 84961, "type": "tap", "zone": "right" }, { "time": 85588, "type": "tap", "zone": "left" }, { "time": 86215, "type": "tap", "zone": "right" }, { "time": 86842, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 86842, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 87492, "type": "tap", "zone": "right" }, { "time": 88119, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 89373, "type": "tap", "zone": "left" }, { "time": 90000, "type": "tap", "zone": "right" }, { "time": 90650, "type": "tap", "zone": "left" }, { "time": 91277, "type": "tap", "zone": "right" }, { "time": 91904, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 91904, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 92531, "type": "tap", "zone": "right" }, { "time": 93158, "type": "tap", "zone": "left" }, { "time": 93808, "type": "tap", "zone": "right" }, { "time": 94435, "type": "tap", "zone": "left" }, { "time": 95062, "type": "tap", "zone": "right" }, { "time": 95689, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 96966, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 96966, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 97593, "type": "tap", "zone": "right" }, { "time": 98220, "type": "tap", "zone": "left" }, { "time": 98870, "type": "tap", "zone": "right" }, { "time": 100101, "type": "tap", "zone": "right" }, { "time": 100751, "type": "tap", "zone": "left" }, { "time": 101378, "type": "tap", "zone": "right" }, { "time": 102005, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 102005, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 102632, "type": "tap", "zone": "right" }, { "time": 103282, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 104536, "type": "tap", "zone": "left" }, { "time": 104936, "type": "tap", "zone": "right" }, { "time": 105790, "type": "tap", "zone": "left" }, { "time": 106440, "type": "tap", "zone": "right" }, { "time": 107067, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 107067, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 107694, "type": "tap", "zone": "right" }, { "time": 108321, "type": "tap", "zone": "left" }, { "time": 108948, "type": "tap", "zone": "right" }, { "time": 109574, "type": "tap", "zone": "left" }, { "time": 109974, "type": "tap", "zone": "right" }, { "time": 110852, "type": "tap", "zone": "left" }, { "time": 111479, "type": "tap", "zone": "right" }, { "time": 112129, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 112129, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 112756, "type": "tap", "zone": "right" }, { "time": 113383, "type": "tap", "zone": "left" }, { "time": 114009, "type": "tap", "zone": "right" }, { "time": 114636, "type": "tap", "zone": "left" }, { "time": 115036, "type": "tap", "zone": "right" }, { "time": 115890, "type": "tap", "zone": "left" }, { "time": 116540, "type": "tap", "zone": "right" }, { "time": 117167, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 117167, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 117794, "type": "tap", "zone": "right" }, { "time": 118421, "type": "tap", "zone": "left" }, { "time": 119071, "type": "tap", "zone": "right" }, { "time": 119698, "type": "tap", "zone": "left" }, { "time": 120302, "type": "tap", "zone": "right" }, { "time": 120952, "type": "tap", "zone": "left" }, { "time": 121602, "type": "tap", "zone": "right" }, { "time": 122229, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 122229, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 122856, "type": "tap", "zone": "right" }, { "time": 123483, "type": "tap", "zone": "left" }, { "time": 124110, "type": "tap", "zone": "right" }, { "time": 124737, "type": "tap", "zone": "left" }, { "time": 125137, "type": "tap", "zone": "right" }, { "time": 126014, "type": "tap", "zone": "left" }, { "time": 126641, "type": "tap", "zone": "right" }, { "time": 127268, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 127268, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 127895, "type": "tap", "zone": "right" }, { "time": 128522, "type": "tap", "zone": "left" }, { "time": 129172, "type": "tap", "zone": "right" }, { "time": 129799, "type": "tap", "zone": "left" }, { "time": 130199, "type": "tap", "zone": "right" }, { "time": 131053, "type": "tap", "zone": "left" }, { "time": 131703, "type": "tap", "zone": "right" }, { "time": 132330, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 132330, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 132957, "type": "tap", "zone": "right" }, { "time": 133584, "type": "tap", "zone": "left" }, { "time": 134211, "type": "tap", "zone": "right" }, { "time": 134838, "type": "tap", "zone": "left" }, { "time": 135238, "type": "tap", "zone": "right" }, { "time": 136115, "type": "tap", "zone": "left" }, { "time": 136672, "type": "tap", "zone": "right" }, { "time": 137856, "type": "tap", "zone": "right" }, { "time": 138483, "type": "tap", "zone": "left" }, { "time": 139760, "type": "tap", "zone": "left" }, { "time": 140387, "type": "tap", "zone": "right" }, { "time": 141664, "type": "tap", "zone": "right" }, { "time": 142291, "type": "tap", "zone": "left" }, { "time": 143592, "type": "tap", "zone": "left" }, { "time": 144288, "type": "tap", "zone": "right" }, { "time": 145705, "type": "tap", "zone": "right" }, { "time": 146308, "type": "tap", "zone": "left" }, { "time": 147516, "type": "tap", "zone": "left" }, { "time": 148143, "type": "tap", "zone": "right" }, { "time": 149397, "type": "tap", "zone": "right" }, { "time": 150024, "type": "tap", "zone": "left" }, { "time": 151278, "type": "tap", "zone": "left" }, { "time": 151904, "type": "tap", "zone": "right" }, { "time": 152531, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 152531, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 153205, "type": "tap", "zone": "right" }, { "time": 153948, "type": "tap", "zone": "left" }, { "time": 154598, "type": "tap", "zone": "right" }, { "time": 155225, "type": "tap", "zone": "left" }, { "time": 155852, "type": "tap", "zone": "right" }, { "time": 156502, "type": "tap", "zone": "left" }, { "time": 157129, "type": "tap", "zone": "right" }, { "time": 157756, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 157756, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 158383, "type": "tap", "zone": "right" }, { "time": 159010, "type": "tap", "zone": "left" }, { "time": 159567, "type": "tap", "zone": "right" }, { "time": 160682, "type": "tap", "zone": "right" }, { "time": 161378, "type": "tap", "zone": "left" }, { "time": 162005, "type": "tap", "zone": "right" }, { "time": 162655, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 162655, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 164536, "type": "tap", "zone": "right" }, { "time": 165163, "type": "tap", "zone": "left" }, { "time": 165563, "type": "tap", "zone": "right" }, { "time": 166440, "type": "tap", "zone": "left" }, { "time": 167067, "type": "tap", "zone": "right" }, { "time": 167694, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 167694, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 168321, "type": "tap", "zone": "right" }, { "time": 168948, "type": "tap", "zone": "left" }, { "time": 169598, "type": "tap", "zone": "right" }, { "time": 170225, "type": "tap", "zone": "left" }, { "time": 170625, "type": "tap", "zone": "right" }, { "time": 171479, "type": "tap", "zone": "left" }, { "time": 172106, "type": "tap", "zone": "right" }, { "time": 172756, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 172756, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 174637, "type": "tap", "zone": "right" }, { "time": 175264, "type": "tap", "zone": "left" }, { "time": 175664, "type": "tap", "zone": "right" }, { "time": 176541, "type": "tap", "zone": "left" }, { "time": 177168, "type": "tap", "zone": "right" }, { "time": 177795, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 177795, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 178422, "type": "tap", "zone": "right" }, { "time": 179049, "type": "tap", "zone": "left" }, { "time": 179629, "type": "tap", "zone": "right" }, { "time": 180210, "type": "tap", "zone": "left" }, { "time": 180813, "type": "tap", "zone": "right" }, { "time": 181440, "type": "tap", "zone": "left" }, { "time": 182067, "type": "tap", "zone": "right" }, { "time": 183344, "type": "tap", "zone": "right" }, { "time": 183994, "type": "tap", "zone": "left" }, { "time": 185225, "type": "tap", "zone": "left" }, { "time": 185852, "type": "tap", "zone": "right" }, { "time": 187129, "type": "tap", "zone": "right" }, { "time": 187733, "type": "tap", "zone": "left" }] }, 'Pixel Paradise': { bpm: 117, scannerCycleDuration: 4000, totalLength: 202106, highScore: storage.highScores && storage.highScores['Pixel Paradise'] || 0, highestGrade: storage.highestGrades && storage.highestGrades['Pixel Paradise'] || 'C', notes: [{ "time": 2000, "type": "tap", "zone": "left" }, { "time": 3000, "type": "tap", "zone": "left" }, { "time": 4000, "type": "tap", "zone": "left" }, { "time": 4500, "type": "tap", "zone": "right" }, { "time": 5000, "type": "tap", "zone": "left" }, { "time": 5500, "type": "tap", "zone": "right" }, { "time": 6000, "type": "tap", "zone": "left", "color": 0xFFA500 }, { "time": 6000, "type": "tap", "zone": "right", "color": 0xFFA500 }, { "time": 7000, "type": "tap", "zone": "right" }, { "time": 8707, "type": "tap", "zone": "right" }, { "time": 9218, "type": "tap", "zone": "left" }, { "time": 9705, "type": "tap", "zone": "right" }, { "time": 10216, "type": "tap", "zone": "left" }, { "time": 10704, "type": "tap", "zone": "right" }, { "time": 11215, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 12701, "type": "tap", "zone": "right" }, { "time": 13212, "type": "tap", "zone": "left" }, { "time": 13699, "type": "tap", "zone": "right" }, { "time": 14210, "type": "tap", "zone": "left" }, { "time": 14610, "type": "tap", "zone": "right" }, { "time": 15209, "type": "tap", "zone": "left" }, { "time": 15696, "type": "tap", "zone": "right" }, { "time": 16207, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 16207, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 18204, "type": "tap", "zone": "left" }, { "time": 18692, "type": "tap", "zone": "right" }, { "time": 19202, "type": "tap", "zone": "left" }, { "time": 19690, "type": "tap", "zone": "right" }, { "time": 20201, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 20201, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 20712, "type": "tap", "zone": "right" }, { "time": 21199, "type": "tap", "zone": "left" }, { "time": 22198, "type": "tap", "zone": "left" }, { "time": 22709, "type": "tap", "zone": "right" }, { "time": 23196, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 24682, "type": "tap", "zone": "right" }, { "time": 25193, "type": "tap", "zone": "left" }, { "time": 25704, "type": "tap", "zone": "right" }, { "time": 26215, "type": "tap", "zone": "left" }, { "time": 26702, "type": "tap", "zone": "right" }, { "time": 27213, "type": "tap", "zone": "left" }, { "time": 27701, "type": "tap", "zone": "right" }, { "time": 28212, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 28212, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 28699, "type": "tap", "zone": "right" }, { "time": 29210, "type": "tap", "zone": "left" }, { "time": 29698, "type": "tap", "zone": "right" }, { "time": 30209, "type": "tap", "zone": "left" }, { "time": 30609, "type": "tap", "zone": "right" }, { "time": 31161, "type": "tap", "zone": "left" }, { "time": 31672, "type": "tap", "zone": "right" }, { "time": 32182, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 32182, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 34202, "type": "tap", "zone": "left" }, { "time": 34602, "type": "tap", "zone": "right" }, { "time": 35201, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 36710, "type": "tap", "zone": "right" }, { "time": 37198, "type": "tap", "zone": "left" }, { "time": 37709, "type": "tap", "zone": "right" }, { "time": 38196, "type": "tap", "zone": "left" }, { "time": 38707, "type": "tap", "zone": "right" }, { "time": 39195, "type": "tap", "zone": "left" }, { "time": 39682, "type": "tap", "zone": "right" }, { "time": 40216, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 40216, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 40704, "type": "tap", "zone": "right" }, { "time": 41215, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 43212, "type": "tap", "zone": "left" }, { "time": 43699, "type": "tap", "zone": "right" }, { "time": 44721, "type": "tap", "zone": "right" }, { "time": 45209, "type": "tap", "zone": "left" }, { "time": 45696, "type": "tap", "zone": "right" }, { "time": 46207, "type": "tap", "zone": "left" }, { "time": 46718, "type": "tap", "zone": "right" }, { "time": 47693, "type": "tap", "zone": "right" }, { "time": 48204, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 48204, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 48715, "type": "tap", "zone": "right" }, { "time": 49203, "type": "tap", "zone": "left" }, { "time": 49713, "type": "tap", "zone": "right" }, { "time": 50201, "type": "tap", "zone": "left" }, { "time": 50712, "type": "tap", "zone": "right" }, { "time": 51200, "type": "tap", "zone": "left" }, { "time": 51710, "type": "tap", "zone": "right" }, { "time": 52221, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 52221, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 52709, "type": "tap", "zone": "right" }, { "time": 53220, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 54706, "type": "tap", "zone": "right" }, { "time": 55217, "type": "tap", "zone": "left" }, { "time": 55704, "type": "tap", "zone": "right" }, { "time": 56192, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 56192, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 56703, "type": "tap", "zone": "right" }, { "time": 57190, "type": "tap", "zone": "left" }, { "time": 57701, "type": "tap", "zone": "right" }, { "time": 58212, "type": "tap", "zone": "left" }, { "time": 58700, "type": "tap", "zone": "right" }, { "time": 59210, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 60696, "type": "tap", "zone": "right" }, { "time": 61207, "type": "tap", "zone": "left" }, { "time": 61695, "type": "tap", "zone": "right" }, { "time": 62183, "type": "tap", "zone": "left" }, { "time": 62693, "type": "tap", "zone": "right" }, { "time": 63204, "type": "tap", "zone": "left" }, { "time": 63715, "type": "tap", "zone": "right" }, { "time": 64203, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 64203, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 64714, "type": "tap", "zone": "right" }, { "time": 65201, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 66710, "type": "tap", "zone": "right" }, { "time": 67198, "type": "tap", "zone": "left" }, { "time": 67709, "type": "tap", "zone": "right" }, { "time": 68220, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 68220, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 68707, "type": "tap", "zone": "right" }, { "time": 69195, "type": "tap", "zone": "left" }, { "time": 69706, "type": "tap", "zone": "right" }, { "time": 70217, "type": "tap", "zone": "left" }, { "time": 70617, "type": "tap", "zone": "right" }, { "time": 71215, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 72701, "type": "tap", "zone": "right" }, { "time": 73189, "type": "tap", "zone": "left" }, { "time": 73700, "type": "tap", "zone": "right" }, { "time": 74210, "type": "tap", "zone": "left" }, { "time": 74698, "type": "tap", "zone": "right" }, { "time": 75209, "type": "tap", "zone": "left" }, { "time": 75697, "type": "tap", "zone": "right" }, { "time": 76207, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 76207, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 76695, "type": "tap", "zone": "right" }, { "time": 77206, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 78692, "type": "tap", "zone": "right" }, { "time": 79203, "type": "tap", "zone": "left" }, { "time": 79690, "type": "tap", "zone": "right" }, { "time": 80201, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 80201, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 80689, "type": "tap", "zone": "right" }, { "time": 81200, "type": "tap", "zone": "left" }, { "time": 81711, "type": "tap", "zone": "right" }, { "time": 82221, "type": "tap", "zone": "left" }, { "time": 82709, "type": "tap", "zone": "right" }, { "time": 83197, "type": "tap", "zone": "left" }, { "time": 83707, "type": "tap", "zone": "right" }, { "time": 84218, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 84218, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 84706, "type": "tap", "zone": "right" }, { "time": 85217, "type": "tap", "zone": "left" }, { "time": 85704, "type": "tap", "zone": "right" }, { "time": 86215, "type": "tap", "zone": "left" }, { "time": 86615, "type": "tap", "zone": "right" }, { "time": 87167, "type": "tap", "zone": "left" }, { "time": 87678, "type": "tap", "zone": "right" }, { "time": 88166, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 88166, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 90209, "type": "tap", "zone": "left" }, { "time": 90609, "type": "tap", "zone": "right" }, { "time": 91184, "type": "tap", "zone": "left" }, { "time": 91695, "type": "tap", "zone": "right" }, { "time": 92206, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 92206, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 92694, "type": "tap", "zone": "right" }, { "time": 93204, "type": "tap", "zone": "left" }, { "time": 93692, "type": "tap", "zone": "right" }, { "time": 94203, "type": "tap", "zone": "left" }, { "time": 94714, "type": "tap", "zone": "right" }, { "time": 95201, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 96711, "type": "tap", "zone": "right" }, { "time": 97221, "type": "tap", "zone": "left" }, { "time": 97709, "type": "tap", "zone": "right" }, { "time": 98197, "type": "tap", "zone": "left" }, { "time": 98708, "type": "tap", "zone": "right" }, { "time": 99195, "type": "tap", "zone": "left" }, { "time": 100217, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 100217, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 100704, "type": "tap", "zone": "right" }, { "time": 101703, "type": "tap", "zone": "right" }, { "time": 102214, "type": "tap", "zone": "left" }, { "time": 103212, "type": "tap", "zone": "left" }, { "time": 103700, "type": "tap", "zone": "right" }, { "time": 104211, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 104211, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 106208, "type": "tap", "zone": "left" }, { "time": 106608, "type": "tap", "zone": "right" }, { "time": 107206, "type": "tap", "zone": "left" }, { "time": 107694, "type": "tap", "zone": "right" }, { "time": 108204, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 108204, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 108692, "type": "tap", "zone": "right" }, { "time": 109203, "type": "tap", "zone": "left" }, { "time": 109691, "type": "tap", "zone": "right" }, { "time": 110201, "type": "tap", "zone": "left" }, { "time": 110601, "type": "tap", "zone": "right" }, { "time": 111200, "type": "tap", "zone": "left" }, { "time": 111711, "type": "tap", "zone": "right" }, { "time": 112198, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 112198, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 114195, "type": "tap", "zone": "left" }, { "time": 114595, "type": "tap", "zone": "right" }, { "time": 115194, "type": "tap", "zone": "left" }, { "time": 115705, "type": "tap", "zone": "right" }, { "time": 116215, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 116215, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 116703, "type": "tap", "zone": "right" }, { "time": 117191, "type": "tap", "zone": "left" }, { "time": 117701, "type": "tap", "zone": "right" }, { "time": 118189, "type": "tap", "zone": "left" }, { "time": 118700, "type": "tap", "zone": "right" }, { "time": 119698, "type": "tap", "zone": "right" }, { "time": 120209, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 120209, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 122206, "type": "tap", "zone": "left" }, { "time": 122606, "type": "tap", "zone": "right" }, { "time": 123205, "type": "tap", "zone": "left" }, { "time": 123715, "type": "tap", "zone": "right" }, { "time": 124203, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 124203, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 124714, "type": "tap", "zone": "right" }, { "time": 125201, "type": "tap", "zone": "left" }, { "time": 125712, "type": "tap", "zone": "right" }, { "time": 126200, "type": "tap", "zone": "left" }, { "time": 126600, "type": "tap", "zone": "right" }, { "time": 127198, "type": "tap", "zone": "left" }, { "time": 127709, "type": "tap", "zone": "right" }, { "time": 128684, "type": "tap", "zone": "right" }, { "time": 129195, "type": "tap", "zone": "left" }, { "time": 130217, "type": "tap", "zone": "left" }, { "time": 130705, "type": "tap", "zone": "right" }, { "time": 131750, "type": "tap", "zone": "right" }, { "time": 132260, "type": "tap", "zone": "left" }, { "time": 133189, "type": "tap", "zone": "left" }, { "time": 133677, "type": "tap", "zone": "right" }, { "time": 134675, "type": "tap", "zone": "right" }, { "time": 135186, "type": "tap", "zone": "left" }, { "time": 136208, "type": "tap", "zone": "left" }, { "time": 136719, "type": "tap", "zone": "right" }, { "time": 137717, "type": "tap", "zone": "right" }, { "time": 138228, "type": "tap", "zone": "left" }, { "time": 139226, "type": "tap", "zone": "left" }, { "time": 139714, "type": "tap", "zone": "right" }, { "time": 140202, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 140202, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 140712, "type": "tap", "zone": "right" }, { "time": 141223, "type": "tap", "zone": "left" }, { "time": 142222, "type": "tap", "zone": "left" }, { "time": 142709, "type": "tap", "zone": "right" }, { "time": 143708, "type": "tap", "zone": "right" }, { "time": 144195, "type": "tap", "zone": "left" }, { "time": 145194, "type": "tap", "zone": "left" }, { "time": 145705, "type": "tap", "zone": "right" }, { "time": 146216, "type": "tap", "zone": "left" }, { "time": 146703, "type": "tap", "zone": "right" }, { "time": 147214, "type": "tap", "zone": "left" }, { "time": 147702, "type": "tap", "zone": "right" }, { "time": 148212, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 148212, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 148700, "type": "tap", "zone": "right" }, { "time": 149699, "type": "tap", "zone": "right" }, { "time": 150209, "type": "tap", "zone": "left" }, { "time": 151208, "type": "tap", "zone": "left" }, { "time": 151695, "type": "tap", "zone": "right" }, { "time": 152206, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 152206, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 154203, "type": "tap", "zone": "left" }, { "time": 154714, "type": "tap", "zone": "right" }, { "time": 155202, "type": "tap", "zone": "left" }, { "time": 155713, "type": "tap", "zone": "right" }, { "time": 156200, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 156200, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 157222, "type": "tap", "zone": "left" }, { "time": 157709, "type": "tap", "zone": "right" }, { "time": 158220, "type": "tap", "zone": "left" }, { "time": 158708, "type": "tap", "zone": "right" }, { "time": 159219, "type": "tap", "zone": "left" }, { "time": 159706, "type": "tap", "zone": "right" }, { "time": 160217, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 160217, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 160728, "type": "tap", "zone": "right" }, { "time": 161726, "type": "tap", "zone": "right" }, { "time": 162214, "type": "tap", "zone": "left" }, { "time": 163213, "type": "tap", "zone": "left" }, { "time": 163700, "type": "tap", "zone": "right" }, { "time": 164211, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 164211, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 164699, "type": "tap", "zone": "right" }, { "time": 165209, "type": "tap", "zone": "left" }, { "time": 165697, "type": "tap", "zone": "right" }, { "time": 166208, "type": "tap", "zone": "left" }, { "time": 166608, "type": "tap", "zone": "right" }, { "time": 167206, "type": "tap", "zone": "left" }, { "time": 167717, "type": "tap", "zone": "right" }, { "time": 168205, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 168205, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 170202, "type": "tap", "zone": "left" }, { "time": 170602, "type": "tap", "zone": "right" }, { "time": 171200, "type": "tap", "zone": "left" }, { "time": 171711, "type": "tap", "zone": "right" }, { "time": 172199, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 172199, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 172710, "type": "tap", "zone": "right" }, { "time": 173197, "type": "tap", "zone": "left" }, { "time": 173708, "type": "tap", "zone": "right" }, { "time": 174196, "type": "tap", "zone": "left" }, { "time": 175217, "type": "tap", "zone": "left" }, { "time": 175705, "type": "tap", "zone": "right" }, { "time": 176216, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 176216, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 176703, "type": "tap", "zone": "right" }, { "time": 177214, "type": "tap", "zone": "left" }, { "time": 177702, "type": "tap", "zone": "right" }, { "time": 178213, "type": "tap", "zone": "left" }, { "time": 178700, "type": "tap", "zone": "right" }, { "time": 179211, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 180697, "type": "tap", "zone": "right" }, { "time": 181208, "type": "tap", "zone": "left" }, { "time": 181719, "type": "tap", "zone": "right" }, { "time": 182206, "type": "tap", "zone": "left" }, { "time": 182606, "type": "tap", "zone": "right" }, { "time": 183205, "type": "tap", "zone": "left" }, { "time": 183716, "type": "tap", "zone": "right" }, { "time": 184203, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 184203, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 184714, "type": "tap", "zone": "right" }, { "time": 185202, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 186711, "type": "tap", "zone": "right" }, { "time": 187222, "type": "tap", "zone": "left" }, { "time": 187710, "type": "tap", "zone": "right" }, { "time": 188197, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 188197, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 188708, "type": "tap", "zone": "right" }, { "time": 189219, "type": "tap", "zone": "left" }, { "time": 189823, "type": "tap", "zone": "right" }, { "time": 190403, "type": "tap", "zone": "left" }, { "time": 190803, "type": "tap", "zone": "right" }, { "time": 191448, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 193468, "type": "tap", "zone": "left" }, { "time": 193956, "type": "tap", "zone": "right" }, { "time": 194954, "type": "tap", "zone": "right" }, { "time": 195465, "type": "tap", "zone": "left" }, { "time": 196464, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 196464, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 196974, "type": "tap", "zone": "right" }, { "time": 197973, "type": "tap", "zone": "right" }, { "time": 198460, "type": "tap", "zone": "left" }, { "time": 198971, "type": "tap", "zone": "right" }] }, 'Runner': { bpm: 92, scannerCycleDuration: 4000, totalLength: 230341, highScore: storage.highScores && storage.highScores['Runner'] || 0, highestGrade: storage.highestGrades && storage.highestGrades['Runner'] || 'C', notes: [{ "time": 208, "type": "tap", "zone": "left" }, { "time": 1671, "type": "tap", "zone": "left" }, { "time": 2972, "type": "tap", "zone": "left" }, { "time": 4272, "type": "tap", "zone": "left" }, { "time": 5247, "type": "tap", "zone": "right" }, { "time": 5572, "type": "tap", "zone": "left" }, { "time": 6873, "type": "tap", "zone": "left" }, { "time": 8173, "type": "tap", "zone": "left" }, { "time": 9496, "type": "tap", "zone": "left" }, { "time": 10472, "type": "tap", "zone": "right" }, { "time": 10797, "type": "tap", "zone": "left" }, { "time": 11772, "type": "tap", "zone": "right" }, { "time": 12097, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 13397, "type": "tap", "zone": "left" }, { "time": 13722, "type": "tap", "zone": "right" }, { "time": 14048, "type": "tap", "zone": "left" }, { "time": 14721, "type": "tap", "zone": "left" }, { "time": 15046, "type": "tap", "zone": "right" }, { "time": 16021, "type": "tap", "zone": "left" }, { "time": 17322, "type": "tap", "zone": "left" }, { "time": 17647, "type": "tap", "zone": "right" }, { "time": 18622, "type": "tap", "zone": "left" }, { "time": 18947, "type": "tap", "zone": "right" }, { "time": 19272, "type": "tap", "zone": "left" }, { "time": 19945, "type": "tap", "zone": "left" }, { "time": 21223, "type": "tap", "zone": "left" }, { "time": 21548, "type": "tap", "zone": "right" }, { "time": 22523, "type": "tap", "zone": "left" }, { "time": 23846, "type": "tap", "zone": "left" }, { "time": 25147, "type": "tap", "zone": "left" }, { "time": 26447, "type": "tap", "zone": "left" }, { "time": 26772, "type": "tap", "zone": "right" }, { "time": 27747, "type": "tap", "zone": "left" }, { "time": 29048, "type": "tap", "zone": "left" }, { "time": 30348, "type": "tap", "zone": "left" }, { "time": 31672, "type": "tap", "zone": "left" }, { "time": 31997, "type": "tap", "zone": "right" }, { "time": 32322, "type": "tap", "zone": "left" }, { "time": 32647, "type": "tap", "zone": "right" }, { "time": 32972, "type": "tap", "zone": "left" }, { "time": 33947, "type": "tap", "zone": "right" }, { "time": 34272, "type": "tap", "zone": "left" }, { "time": 34597, "type": "tap", "zone": "right" }, { "time": 34922, "type": "tap", "zone": "left" }, { "time": 35247, "type": "tap", "zone": "right" }, { "time": 35572, "type": "tap", "zone": "left" }, { "time": 36873, "type": "tap", "zone": "left" }, { "time": 38173, "type": "tap", "zone": "left" }, { "time": 39497, "type": "tap", "zone": "left" }, { "time": 40797, "type": "tap", "zone": "left" }, { "time": 42097, "type": "tap", "zone": "left" }, { "time": 42422, "type": "tap", "zone": "right" }, { "time": 42747, "type": "tap", "zone": "left" }, { "time": 43073, "type": "tap", "zone": "right" }, { "time": 43398, "type": "tap", "zone": "left" }, { "time": 43723, "type": "tap", "zone": "right" }, { "time": 44048, "type": "tap", "zone": "left" }, { "time": 44373, "type": "tap", "zone": "right" }, { "time": 44698, "type": "tap", "zone": "left" }, { "time": 45023, "type": "tap", "zone": "right" }, { "time": 45348, "type": "tap", "zone": "left" }, { "time": 45673, "type": "tap", "zone": "right" }, { "time": 45998, "type": "tap", "zone": "left" }, { "time": 46323, "type": "tap", "zone": "right" }, { "time": 46648, "type": "tap", "zone": "left" }, { "time": 46985, "type": "tap", "zone": "right" }, { "time": 47322, "type": "tap", "zone": "left" }, { "time": 47647, "type": "tap", "zone": "right" }, { "time": 47972, "type": "tap", "zone": "left" }, { "time": 48622, "type": "tap", "zone": "left" }, { "time": 48947, "type": "tap", "zone": "right" }, { "time": 49272, "type": "tap", "zone": "left" }, { "time": 49597, "type": "tap", "zone": "right" }, { "time": 49922, "type": "tap", "zone": "left" }, { "time": 50247, "type": "tap", "zone": "right" }, { "time": 50573, "type": "tap", "zone": "left" }, { "time": 51223, "type": "tap", "zone": "left" }, { "time": 51896, "type": "tap", "zone": "left" }, { "time": 52221, "type": "tap", "zone": "right" }, { "time": 52546, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 52546, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 52871, "type": "tap", "zone": "right" }, { "time": 53196, "type": "tap", "zone": "left" }, { "time": 53521, "type": "tap", "zone": "right" }, { "time": 53847, "type": "tap", "zone": "left" }, { "time": 54172, "type": "tap", "zone": "right" }, { "time": 54822, "type": "tap", "zone": "right" }, { "time": 55147, "type": "tap", "zone": "left" }, { "time": 55472, "type": "tap", "zone": "right" }, { "time": 56122, "type": "tap", "zone": "right" }, { "time": 56447, "type": "tap", "zone": "left" }, { "time": 56772, "type": "tap", "zone": "right" }, { "time": 57422, "type": "tap", "zone": "right" }, { "time": 57748, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 57748, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 58073, "type": "tap", "zone": "right" }, { "time": 58398, "type": "tap", "zone": "left" }, { "time": 58723, "type": "tap", "zone": "right" }, { "time": 59048, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 60371, "type": "tap", "zone": "left" }, { "time": 60696, "type": "tap", "zone": "right" }, { "time": 61022, "type": "tap", "zone": "left" }, { "time": 61347, "type": "tap", "zone": "right" }, { "time": 61672, "type": "tap", "zone": "left" }, { "time": 61997, "type": "tap", "zone": "right" }, { "time": 62322, "type": "tap", "zone": "left" }, { "time": 62647, "type": "tap", "zone": "right" }, { "time": 62972, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 62972, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 63297, "type": "tap", "zone": "right" }, { "time": 63622, "type": "tap", "zone": "left" }, { "time": 63947, "type": "tap", "zone": "right" }, { "time": 64272, "type": "tap", "zone": "left" }, { "time": 64597, "type": "tap", "zone": "right" }, { "time": 64922, "type": "tap", "zone": "left" }, { "time": 65248, "type": "tap", "zone": "right" }, { "time": 65573, "type": "tap", "zone": "left" }, { "time": 65898, "type": "tap", "zone": "right" }, { "time": 66223, "type": "tap", "zone": "left" }, { "time": 66548, "type": "tap", "zone": "right" }, { "time": 66873, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 67871, "type": "tap", "zone": "right" }, { "time": 68197, "type": "tap", "zone": "left" }, { "time": 68522, "type": "tap", "zone": "right" }, { "time": 69172, "type": "tap", "zone": "right" }, { "time": 69497, "type": "tap", "zone": "left" }, { "time": 69822, "type": "tap", "zone": "right" }, { "time": 70147, "type": "tap", "zone": "left" }, { "time": 70472, "type": "tap", "zone": "right" }, { "time": 70797, "type": "tap", "zone": "left" }, { "time": 71122, "type": "tap", "zone": "right" }, { "time": 71447, "type": "tap", "zone": "left" }, { "time": 71772, "type": "tap", "zone": "right" }, { "time": 72097, "type": "tap", "zone": "left" }, { "time": 73398, "type": "tap", "zone": "left" }, { "time": 73723, "type": "tap", "zone": "right" }, { "time": 74048, "type": "tap", "zone": "left" }, { "time": 74373, "type": "tap", "zone": "right" }, { "time": 74698, "type": "tap", "zone": "left" }, { "time": 76022, "type": "tap", "zone": "left" }, { "time": 76347, "type": "tap", "zone": "right" }, { "time": 76997, "type": "tap", "zone": "right" }, { "time": 77322, "type": "tap", "zone": "left" }, { "time": 78297, "type": "tap", "zone": "right" }, { "time": 78622, "type": "tap", "zone": "left" }, { "time": 78947, "type": "tap", "zone": "right" }, { "time": 79272, "type": "tap", "zone": "left" }, { "time": 79923, "type": "tap", "zone": "left" }, { "time": 81223, "type": "tap", "zone": "left" }, { "time": 81548, "type": "tap", "zone": "right" }, { "time": 81873, "type": "tap", "zone": "left" }, { "time": 82198, "type": "tap", "zone": "right" }, { "time": 82523, "type": "tap", "zone": "left" }, { "time": 83173, "type": "tap", "zone": "left" }, { "time": 83510, "type": "tap", "zone": "right" }, { "time": 83847, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 83847, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 84172, "type": "tap", "zone": "right" }, { "time": 84497, "type": "tap", "zone": "left" }, { "time": 84822, "type": "tap", "zone": "right" }, { "time": 85147, "type": "tap", "zone": "left" }, { "time": 85472, "type": "tap", "zone": "right" }, { "time": 85797, "type": "tap", "zone": "left" }, { "time": 86122, "type": "tap", "zone": "right" }, { "time": 86447, "type": "tap", "zone": "left" }, { "time": 86772, "type": "tap", "zone": "right" }, { "time": 87098, "type": "tap", "zone": "left" }, { "time": 87423, "type": "tap", "zone": "right" }, { "time": 87748, "type": "tap", "zone": "left" }, { "time": 88073, "type": "tap", "zone": "right" }, { "time": 88398, "type": "tap", "zone": "left" }, { "time": 88723, "type": "tap", "zone": "right" }, { "time": 89048, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 89048, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 89373, "type": "tap", "zone": "right" }, { "time": 90348, "type": "tap", "zone": "left" }, { "time": 91335, "type": "tap", "zone": "right" }, { "time": 91672, "type": "tap", "zone": "left" }, { "time": 91997, "type": "tap", "zone": "right" }, { "time": 92322, "type": "tap", "zone": "left" }, { "time": 92647, "type": "tap", "zone": "right" }, { "time": 92972, "type": "tap", "zone": "left" }, { "time": 93297, "type": "tap", "zone": "right" }, { "time": 93622, "type": "tap", "zone": "left" }, { "time": 93947, "type": "tap", "zone": "right" }, { "time": 94273, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 94273, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 94598, "type": "tap", "zone": "right" }, { "time": 94923, "type": "tap", "zone": "left" }, { "time": 95248, "type": "tap", "zone": "right" }, { "time": 95573, "type": "tap", "zone": "left" }, { "time": 95898, "type": "tap", "zone": "right" }, { "time": 96223, "type": "tap", "zone": "left" }, { "time": 96548, "type": "tap", "zone": "right" }, { "time": 96873, "type": "tap", "zone": "left" }, { "time": 97198, "type": "tap", "zone": "right" }, { "time": 97523, "type": "tap", "zone": "left" }, { "time": 97848, "type": "tap", "zone": "right" }, { "time": 98173, "type": "tap", "zone": "left" }, { "time": 98499, "type": "tap", "zone": "right" }, { "time": 98824, "type": "tap", "zone": "left" }, { "time": 99160, "type": "tap", "zone": "right" }, { "time": 99497, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 99497, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 99822, "type": "tap", "zone": "right" }, { "time": 100147, "type": "tap", "zone": "left" }, { "time": 100472, "type": "tap", "zone": "right" }, { "time": 100797, "type": "tap", "zone": "left" }, { "time": 101122, "type": "tap", "zone": "right" }, { "time": 101447, "type": "tap", "zone": "left" }, { "time": 101773, "type": "tap", "zone": "right" }, { "time": 102098, "type": "tap", "zone": "left" }, { "time": 103421, "type": "tap", "zone": "left" }, { "time": 104396, "type": "tap", "zone": "right" }, { "time": 104721, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 104721, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 106672, "type": "tap", "zone": "left" }, { "time": 106997, "type": "tap", "zone": "right" }, { "time": 107322, "type": "tap", "zone": "left" }, { "time": 107647, "type": "tap", "zone": "right" }, { "time": 107972, "type": "tap", "zone": "left" }, { "time": 108297, "type": "tap", "zone": "right" }, { "time": 108622, "type": "tap", "zone": "left" }, { "time": 108948, "type": "tap", "zone": "right" }, { "time": 109273, "type": "tap", "zone": "left" }, { "time": 109598, "type": "tap", "zone": "right" }, { "time": 109923, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 109923, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 110248, "type": "tap", "zone": "right" }, { "time": 110573, "type": "tap", "zone": "left" }, { "time": 110898, "type": "tap", "zone": "right" }, { "time": 111223, "type": "tap", "zone": "left" }, { "time": 111548, "type": "tap", "zone": "right" }, { "time": 111873, "type": "tap", "zone": "left" }, { "time": 112210, "type": "tap", "zone": "right" }, { "time": 112547, "type": "tap", "zone": "left" }, { "time": 112872, "type": "tap", "zone": "right" }, { "time": 113197, "type": "tap", "zone": "left" }, { "time": 113522, "type": "tap", "zone": "right" }, { "time": 113847, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 114822, "type": "tap", "zone": "right" }, { "time": 115147, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 115147, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 117098, "type": "tap", "zone": "left" }, { "time": 117423, "type": "tap", "zone": "right" }, { "time": 117748, "type": "tap", "zone": "left" }, { "time": 118073, "type": "tap", "zone": "right" }, { "time": 118398, "type": "tap", "zone": "left" }, { "time": 118723, "type": "tap", "zone": "right" }, { "time": 119048, "type": "tap", "zone": "left" }, { "time": 119385, "type": "tap", "zone": "right" }, { "time": 119722, "type": "tap", "zone": "left" }, { "time": 120047, "type": "tap", "zone": "right" }, { "time": 120372, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 120372, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 120697, "type": "tap", "zone": "right" }, { "time": 121022, "type": "tap", "zone": "left" }, { "time": 121347, "type": "tap", "zone": "right" }, { "time": 121672, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 122322, "type": "tap", "zone": "left" }, { "time": 122972, "type": "tap", "zone": "left" }, { "time": 123297, "type": "tap", "zone": "right" }, { "time": 123623, "type": "tap", "zone": "left" }, { "time": 123948, "type": "tap", "zone": "right" }, { "time": 124273, "type": "tap", "zone": "left" }, { "time": 125573, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 125573, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 125898, "type": "tap", "zone": "right" }, { "time": 126548, "type": "tap", "zone": "right" }, { "time": 126873, "type": "tap", "zone": "left" }, { "time": 127198, "type": "tap", "zone": "right" }, { "time": 127523, "type": "tap", "zone": "left" }, { "time": 127849, "type": "tap", "zone": "right" }, { "time": 128174, "type": "tap", "zone": "left" }, { "time": 128510, "type": "tap", "zone": "right" }, { "time": 129172, "type": "tap", "zone": "right" }, { "time": 129497, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 130472, "type": "tap", "zone": "right" }, { "time": 130798, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 130798, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 131123, "type": "tap", "zone": "right" }, { "time": 131448, "type": "tap", "zone": "left" }, { "time": 131773, "type": "tap", "zone": "right" }, { "time": 132098, "type": "tap", "zone": "left" }, { "time": 132423, "type": "tap", "zone": "right" }, { "time": 132748, "type": "tap", "zone": "left" }, { "time": 133073, "type": "tap", "zone": "right" }, { "time": 133398, "type": "tap", "zone": "left" }, { "time": 133723, "type": "tap", "zone": "right" }, { "time": 134373, "type": "tap", "zone": "right" }, { "time": 134698, "type": "tap", "zone": "left" }, { "time": 135035, "type": "tap", "zone": "right" }, { "time": 135372, "type": "tap", "zone": "left" }, { "time": 135697, "type": "tap", "zone": "right" }, { "time": 136022, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 136022, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 136347, "type": "tap", "zone": "right" }, { "time": 136672, "type": "tap", "zone": "left" }, { "time": 136997, "type": "tap", "zone": "right" }, { "time": 137322, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 138623, "type": "tap", "zone": "left" }, { "time": 138948, "type": "tap", "zone": "right" }, { "time": 139598, "type": "tap", "zone": "right" }, { "time": 139923, "type": "tap", "zone": "left" }, { "time": 140248, "type": "tap", "zone": "right" }, { "time": 140573, "type": "tap", "zone": "left" }, { "time": 140898, "type": "tap", "zone": "right" }, { "time": 141223, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 141223, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 141548, "type": "tap", "zone": "right" }, { "time": 141873, "type": "tap", "zone": "left" }, { "time": 142199, "type": "tap", "zone": "right" }, { "time": 142524, "type": "tap", "zone": "left" }, { "time": 142849, "type": "tap", "zone": "right" }, { "time": 143174, "type": "tap", "zone": "left" }, { "time": 143510, "type": "tap", "zone": "right" }, { "time": 143847, "type": "tap", "zone": "left" }, { "time": 144172, "type": "tap", "zone": "right" }, { "time": 144497, "type": "tap", "zone": "left" }, { "time": 144822, "type": "tap", "zone": "right" }, { "time": 145147, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 146123, "type": "tap", "zone": "right" }, { "time": 146448, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 146448, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 146773, "type": "tap", "zone": "right" }, { "time": 147098, "type": "tap", "zone": "left" }, { "time": 147423, "type": "tap", "zone": "right" }, { "time": 147748, "type": "tap", "zone": "left" }, { "time": 148073, "type": "tap", "zone": "right" }, { "time": 148398, "type": "tap", "zone": "left" }, { "time": 148723, "type": "tap", "zone": "right" }, { "time": 149048, "type": "tap", "zone": "left" }, { "time": 149373, "type": "tap", "zone": "right" }, { "time": 149699, "type": "tap", "zone": "left" }, { "time": 150024, "type": "tap", "zone": "right" }, { "time": 150349, "type": "tap", "zone": "left" }, { "time": 150685, "type": "tap", "zone": "right" }, { "time": 151022, "type": "tap", "zone": "left" }, { "time": 151347, "type": "tap", "zone": "right" }, { "time": 151672, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 151672, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 151997, "type": "tap", "zone": "right" }, { "time": 152322, "type": "tap", "zone": "left" }, { "time": 152647, "type": "tap", "zone": "right" }, { "time": 152973, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 154273, "type": "tap", "zone": "left" }, { "time": 154598, "type": "tap", "zone": "right" }, { "time": 154923, "type": "tap", "zone": "left" }, { "time": 155573, "type": "tap", "zone": "left" }, { "time": 156874, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 156874, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 158174, "type": "tap", "zone": "left" }, { "time": 159161, "type": "tap", "zone": "right" }, { "time": 159497, "type": "tap", "zone": "left" }, { "time": 159822, "type": "tap", "zone": "right" }, { "time": 160148, "type": "tap", "zone": "left" }, { "time": 160473, "type": "tap", "zone": "right" }, { "time": 160798, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 161773, "type": "tap", "zone": "right" }, { "time": 162098, "type": "tap", "zone": "left" }, { "time": 163398, "type": "tap", "zone": "left" }, { "time": 164374, "type": "tap", "zone": "right" }, { "time": 164699, "type": "tap", "zone": "left" }, { "time": 165024, "type": "tap", "zone": "right" }, { "time": 165349, "type": "tap", "zone": "left" }, { "time": 165674, "type": "tap", "zone": "right" }, { "time": 165999, "type": "tap", "zone": "left" }, { "time": 166324, "type": "tap", "zone": "right" }, { "time": 166649, "type": "tap", "zone": "left" }, { "time": 166986, "type": "tap", "zone": "right" }, { "time": 167322, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 167322, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 167973, "type": "tap", "zone": "left" }, { "time": 168623, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 169923, "type": "tap", "zone": "left" }, { "time": 170573, "type": "tap", "zone": "left" }, { "time": 171223, "type": "tap", "zone": "left" }, { "time": 171874, "type": "tap", "zone": "left" }, { "time": 172199, "type": "tap", "zone": "right" }, { "time": 172524, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 172524, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 172849, "type": "tap", "zone": "right" }, { "time": 173174, "type": "tap", "zone": "left" }, { "time": 173499, "type": "tap", "zone": "right" }, { "time": 173824, "type": "tap", "zone": "left" }, { "time": 174161, "type": "tap", "zone": "right" }, { "time": 174497, "type": "tap", "zone": "left" }, { "time": 175148, "type": "tap", "zone": "left" }, { "time": 175473, "type": "tap", "zone": "right" }, { "time": 175798, "type": "tap", "zone": "left" }, { "time": 176587, "type": "tap", "zone": "left" }, { "time": 177528, "type": "tap", "zone": "right" }, { "time": 177818, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 177818, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 179699, "type": "tap", "zone": "left" }, { "time": 180024, "type": "tap", "zone": "right" }, { "time": 180349, "type": "tap", "zone": "left" }, { "time": 180674, "type": "tap", "zone": "right" }, { "time": 180999, "type": "tap", "zone": "left" }, { "time": 181324, "type": "tap", "zone": "right" }, { "time": 181649, "type": "tap", "zone": "left" }, { "time": 181974, "type": "tap", "zone": "right" }, { "time": 182299, "type": "tap", "zone": "left" }, { "time": 182624, "type": "tap", "zone": "right" }, { "time": 182950, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 182950, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 183275, "type": "tap", "zone": "right" }, { "time": 183600, "type": "tap", "zone": "left" }, { "time": 183925, "type": "tap", "zone": "right" }, { "time": 184250, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 185550, "type": "tap", "zone": "left" }, { "time": 185887, "type": "tap", "zone": "right" }, { "time": 186224, "type": "tap", "zone": "left" }, { "time": 186549, "type": "tap", "zone": "right" }, { "time": 186874, "type": "tap", "zone": "left" }, { "time": 187524, "type": "tap", "zone": "left" }, { "time": 187849, "type": "tap", "zone": "right" }, { "time": 188174, "type": "hold", "zone": "left", "duration": 1500, "color": 16753920 }, { "time": 188174, "type": "hold", "zone": "right", "duration": 1500, "color": 16753920 }, { "time": 190124, "type": "tap", "zone": "left" }, { "time": 190450, "type": "tap", "zone": "right" }, { "time": 190775, "type": "tap", "zone": "left" }, { "time": 191100, "type": "tap", "zone": "right" }, { "time": 191425, "type": "tap", "zone": "left" }, { "time": 191750, "type": "tap", "zone": "right" }, { "time": 192075, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 192400, "type": "tap", "zone": "right" }, { "time": 193399, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 193399, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 194699, "type": "tap", "zone": "left" }, { "time": 195674, "type": "tap", "zone": "right" }, { "time": 195999, "type": "tap", "zone": "left" }, { "time": 196324, "type": "tap", "zone": "right" }, { "time": 196649, "type": "tap", "zone": "left" }, { "time": 196974, "type": "tap", "zone": "right" }, { "time": 197299, "type": "tap", "zone": "left" }, { "time": 198600, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 198600, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 199900, "type": "tap", "zone": "left" }, { "time": 201200, "type": "tap", "zone": "left" }, { "time": 201851, "type": "tap", "zone": "left" }, { "time": 202524, "type": "tap", "zone": "left" }, { "time": 203174, "type": "tap", "zone": "left" }, { "time": 203499, "type": "tap", "zone": "right" }, { "time": 203824, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 203824, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 205125, "type": "tap", "zone": "left" }, { "time": 205775, "type": "tap", "zone": "left" }, { "time": 206425, "type": "tap", "zone": "left" }, { "time": 207075, "type": "tap", "zone": "left" }, { "time": 207725, "type": "hold", "zone": "left", "duration": 1000 }, { "time": 208724, "type": "tap", "zone": "right" }, { "time": 209049, "type": "tap", "zone": "left", "color": 16753920 }, { "time": 209049, "type": "tap", "zone": "right", "color": 16753920 }, { "time": 209699, "type": "tap", "zone": "left" }, { "time": 210349, "type": "tap", "zone": "left" }, { "time": 211649, "type": "tap", "zone": "left" }, { "time": 212950, "type": "tap", "zone": "left" }, { "time": 213600, "type": "tap", "zone": "left" }, { "time": 214250, "type": "tap", "zone": "left" }, { "time": 214900, "type": "tap", "zone": "left" }, { "time": 215550, "type": "hold", "zone": "right", "duration": 1000 }, { "time": 216874, "type": "tap", "zone": "left" }, { "time": 217524, "type": "tap", "zone": "left" }, { "time": 217849, "type": "tap", "zone": "right" }, { "time": 218174, "type": "tap", "zone": "left" }, { "time": 218499, "type": "tap", "zone": "right" }, { "time": 218824, "type": "tap", "zone": "left" }, { "time": 219428, "type": "tap", "zone": "left" }, { "time": 220636, "type": "tap", "zone": "left" }, { "time": 221936, "type": "tap", "zone": "left" }, { "time": 223236, "type": "tap", "zone": "left" }, { "time": 224536, "type": "tap", "zone": "left" }, { "time": 225837, "type": "tap", "zone": "left" }, { "time": 227137, "type": "tap", "zone": "left" }] } }; function getSongLength(songName) { var song = SongDatabase[songName]; if (!song) { return "0:00"; } var totalSeconds = Math.floor(song.totalLength / 1000); var minutes = Math.floor(totalSeconds / 60); var seconds = totalSeconds % 60; return minutes + ":" + (seconds < 10 ? "0" : "") + seconds; } function updateHighScore(songName, score, grade) { var updated = false; if (SongDatabase[songName]) { if (score > SongDatabase[songName].highScore) { SongDatabase[songName].highScore = score; // Save high scores to storage if (!storage.highScores) { storage.highScores = {}; } storage.highScores[songName] = score; updated = true; } // Update grade if it's better (S > A > B > C) var currentGrade = SongDatabase[songName].highestGrade || 'C'; var gradeOrder = ['C', 'B', 'A', 'S']; if (gradeOrder.indexOf(grade) > gradeOrder.indexOf(currentGrade)) { SongDatabase[songName].highestGrade = grade; // Save highest grades to storage if (!storage.highestGrades) { storage.highestGrades = {}; } storage.highestGrades[songName] = grade; updated = true; } } return updated; } function calculateNotePosition(noteTime) { var cycleTime = noteTime % SCANNER_CYCLE_DURATION; var y; if (cycleTime < SCANNER_HALF_CYCLE) { var progress = cycleTime / SCANNER_HALF_CYCLE; y = SCANNER_Y_MAX - progress * PLAY_AREA_HEIGHT; } else { var progress = (cycleTime - SCANNER_HALF_CYCLE) / SCANNER_HALF_CYCLE; y = SCANNER_Y_MIN + progress * PLAY_AREA_HEIGHT; } return y; } function calculateZoneX(zone, noteY, endNoteY) { var sideMargin = GAME_WIDTH * SAFETY_MARGIN_SIDES_PERCENT; var randomSpan = GAME_WIDTH / 2 - 2 * sideMargin; if (randomSpan < 0) { randomSpan = 0; } // Check if note or its end note is in the bottom 15% of the play area var isInBottomArea = noteY > SCANNER_Y_MAX - PLAY_AREA_HEIGHT * 0.20; if (endNoteY !== undefined) { isInBottomArea = isInBottomArea || endNoteY > SCANNER_Y_MAX - PLAY_AREA_HEIGHT * 0.15; } var xPosition; if (zone === 'left') { xPosition = sideMargin; if (isInBottomArea) { // In bottom area, favor the right side of the left zone (more central) // Use the right 60% of the left zone's available space var centralSpan = randomSpan * 0.5; var offset = randomSpan * 0.5; // Skip the leftmost 40% xPosition += offset + Math.random() * centralSpan; } else { // Normal positioning for upper areas xPosition += Math.random() * randomSpan; } } else { xPosition = GAME_WIDTH / 2 + sideMargin; if (isInBottomArea) { // In bottom area, favor the left side of the right zone (more central) // Use the left 60% of the right zone's available space var centralSpan = randomSpan * 0.5; xPosition += Math.random() * centralSpan; } else { // Normal positioning for upper areas xPosition += Math.random() * randomSpan; } } return xPosition; } function createZoneIndicators() { leftZone = game.attachAsset('zoneIndicator', { anchorX: 0, anchorY: 0 }); leftZone.x = 0; leftZone.y = 0; leftZone.width = GAME_WIDTH / 2; leftZone.alpha = 0.1; leftZone.tint = 0x00ffff; rightZone = game.attachAsset('zoneIndicator', { anchorX: 0, anchorY: 0 }); rightZone.x = GAME_WIDTH / 2; rightZone.y = 0; rightZone.width = GAME_WIDTH / 2; rightZone.alpha = 0.1; rightZone.tint = 0xff00ff; } function showAccuracyPopup(text, x, y, color) { var popup = new Text2(text, { size: ACCURACY_POPUP_FONT_SIZE, fill: color, stroke: 0x000000, strokeThickness: 4 }); popup.anchor.set(0.5, 0.5); popup.x = x; popup.y = y + ACCURACY_POPUP_Y_OFFSET; popup.alpha = 0; game.addChild(popup); var initialY = popup.y; tween(popup, { alpha: 1, y: initialY - 30 }, { duration: ACCURACY_POPUP_DURATION * 0.25, easing: tween.easeOut, onFinish: function onFinish() { tween(popup, { alpha: 0, y: initialY - 130 }, { duration: ACCURACY_POPUP_DURATION * 0.75, easing: tween.easeIn, onFinish: function onFinish() { if (popup && popup.destroy) { popup.destroy(); } } }); } }); } function initializeTitleScreen() { titleScreen.container = new Container(); game.addChild(titleScreen.container); titleScreen.title = titleScreen.container.attachAsset('titleImage', { anchorX: 0.5, anchorY: 0.5 }); titleScreen.title.x = GAME_WIDTH / 2; titleScreen.title.y = GAME_HEIGHT / 2 - 200; titleScreen.subtitle = new Text2('Press to Start', { size: 100, fill: 0xCCCCCC }); titleScreen.subtitle.anchor.set(0.5, 0.5); titleScreen.subtitle.x = GAME_WIDTH / 2; titleScreen.subtitle.y = GAME_HEIGHT / 2 + 100 + GAME_HEIGHT * 0.15; titleScreen.container.addChild(titleScreen.subtitle); var pulseScale = 1; var pulseDirection = 1; titleScreen.pulseInterval = LK.setInterval(function () { pulseScale += pulseDirection * 0.02; if (pulseScale > 1.1) { pulseScale = 1.1; pulseDirection = -1; } else if (pulseScale < 0.9) { pulseScale = 0.9; pulseDirection = 1; } titleScreen.subtitle.scale.set(pulseScale); }, 50); } function initializeSongSelectScreen() { songSelectScreen.container = new Container(); game.addChild(songSelectScreen.container); songSelectScreen.container.visible = false; songSelectScreen.title = new Text2('Select Song', { size: 150, fill: 0xFFFFFF }); songSelectScreen.title.anchor.set(0.5, 0); songSelectScreen.title.x = GAME_WIDTH / 2; songSelectScreen.title.y = 100; songSelectScreen.container.addChild(songSelectScreen.title); songSelectScreen.scrollContainer = new Container(); songSelectScreen.scrollContainer.x = 0; songSelectScreen.scrollContainer.y = 300; songSelectScreen.container.addChild(songSelectScreen.scrollContainer); createSongItems(); updateScrollLimits(); songSelectScreen.tutorialButton = new Text2('How to Play', { size: 90, fill: 0xCCCCCC }); songSelectScreen.tutorialButton.anchor.set(0.5, 1); songSelectScreen.tutorialButton.x = GAME_WIDTH / 2; songSelectScreen.tutorialButton.y = GAME_HEIGHT - 60; // Positioned at the bottom songSelectScreen.container.addChild(songSelectScreen.tutorialButton); } function createSongItems() { songSelectScreen.items = []; var songNames = Object.keys(SongDatabase); for (var i = 0; i < songNames.length; i++) { var songName = songNames[i]; var song = SongDatabase[songName]; var yPos = i * (SONG_ITEM_HEIGHT + 50); var itemContainer = new Container(); itemContainer.x = 100; itemContainer.y = yPos; itemContainer.songName = songName; var bg = game.attachAsset('zoneIndicator', { anchorX: 0, anchorY: 0 }); bg.width = GAME_WIDTH - 200; bg.height = SONG_ITEM_HEIGHT; bg.alpha = 0.2; bg.tint = 0x333333; itemContainer.addChild(bg); var displayName = songName; if (songName === 'Runner') { displayName = songName + ' (Hard)'; } var titleText = new Text2(displayName, { size: 100, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); // Center horizontally, align top vertically titleText.x = (GAME_WIDTH - 200) / 2; // Center within the background width titleText.y = 30; itemContainer.addChild(titleText); // Define vertical padding between text elements var verticalPadding = 20; var infoText = new Text2('BPM: ' + song.bpm + ' | Length: ' + getSongLength(songName), { size: 62.5, fill: 0xCCCCCC }); infoText.anchor.set(0.5, 0); // Center horizontally, align top vertically infoText.x = (GAME_WIDTH - 200) / 2; // Center within the background width // Position infoText below titleText (assuming titleText font size 100 is approx height) infoText.y = titleText.y + 100 + verticalPadding; itemContainer.addChild(infoText); var gradeDisplay = song.highestGrade || 'C'; var scoreText = new Text2('High Score: ' + song.highScore + ' | Grade: ' + gradeDisplay, { size: 62.5, fill: 0xFFDD00 }); scoreText.anchor.set(0.5, 0); // Center horizontally, align top vertically scoreText.x = (GAME_WIDTH - 200) / 2; // Center within the background width // Position scoreText below infoText (assuming infoText font size 62.5 is approx height) scoreText.y = infoText.y + 62.5 + verticalPadding; itemContainer.addChild(scoreText); songSelectScreen.scrollContainer.addChild(itemContainer); songSelectScreen.items.push(itemContainer); } } function updateScrollLimits() { var totalHeight = songSelectScreen.items.length * (SONG_ITEM_HEIGHT + 50); var containerHeight = GAME_HEIGHT - 400; maxScrollY = Math.max(0, totalHeight - containerHeight); } function showTitleScreen() { currentGameState = GAME_STATE_TITLE; if (titleScreen.container) { titleScreen.container.visible = true; } if (songSelectScreen.container) { songSelectScreen.container.visible = false; } if (resultsScreen.container) { resultsScreen.container.visible = false; } if (tutorialScreen.container) { tutorialScreen.container.visible = false; } hideGameplayUI(); } function showSongSelectScreen() { currentGameState = GAME_STATE_SONG_SELECT; if (titleScreen.container) { titleScreen.container.visible = false; } if (songSelectScreen.container) { songSelectScreen.container.visible = true; } if (resultsScreen.container) { resultsScreen.container.visible = false; } if (tutorialScreen.container) { tutorialScreen.container.visible = false; } songSelectionInProgress = false; // Reset flag when song select screen is shown hideGameplayUI(); songSelectScrollY = 0; songSelectScreen.scrollContainer.y = 300; } function hideGameplayUI() { if (scoreTxt) { scoreTxt.visible = false; } // Zone indicators removed - no longer hiding background zones // if (leftZone) { // leftZone.visible = false; // } // if (rightZone) { // rightZone.visible = false; // } if (scanner) { scanner.visible = false; } // Also ensure tutorial is hidden if gameplay UI is hidden for other reasons if (tutorialScreen.container && currentGameState !== GAME_STATE_TUTORIAL) { tutorialScreen.container.visible = false; } } function showGameplayUI() { if (scoreTxt) { scoreTxt.visible = true; } // Zone indicators removed - no longer showing background zones // if (leftZone) { // leftZone.visible = true; // } // if (rightZone) { // rightZone.visible = true; // } if (scanner) { scanner.visible = true; } if (titleScreen.container) { titleScreen.container.visible = false; } if (songSelectScreen.container) { songSelectScreen.container.visible = false; } if (tutorialScreen.container) { tutorialScreen.container.visible = false; } if (resultsScreen.container) { resultsScreen.container.visible = false; } } function startCountdown() { countdownTxt = new Text2('3', { size: 200, fill: 0xFFFFFF }); countdownTxt.anchor.set(0.5, 0.5); countdownTxt.x = GAME_WIDTH / 2; countdownTxt.y = GAME_HEIGHT / 2; game.addChild(countdownTxt); // Start countdown acceleration isCountdownActive = true; countdownAcceleration = 1; var startTime = Date.now(); var countdownDuration = 4000; // 4 seconds total var count = 3; var countdownInterval = LK.setInterval(function () { count--; if (count > 0) { countdownTxt.setText(count.toString()); } else if (count === 0) { countdownTxt.setText('GO!'); } else { LK.clearInterval(countdownInterval); if (countdownTxt && countdownTxt.destroy) { countdownTxt.destroy(); } // Keep the accelerated speed when game starts baseParticleSpeed = 5; // Maintain 5x speed isCountdownActive = false; countdownAcceleration = 1; startGame(); } }, 1000); // Smooth acceleration during countdown var accelerationInterval = LK.setInterval(function () { if (!isCountdownActive) { LK.clearInterval(accelerationInterval); return; } var elapsed = Date.now() - startTime; var progress = Math.min(elapsed / countdownDuration, 1); // Smooth acceleration curve - starts slow, ramps up faster var easedProgress = progress * progress; countdownAcceleration = 1 + easedProgress * 4; // 1x to 5x speed }, 50); // Update every 50ms for smooth acceleration } function showResultsScreen() { currentGameState = GAME_STATE_RESULTS; if (titleScreen.container) { titleScreen.container.visible = false; } if (songSelectScreen.container) { songSelectScreen.container.visible = false; } if (resultsScreen.container) { resultsScreen.container.visible = true; } if (tutorialScreen.container) { tutorialScreen.container.visible = false; } hideGameplayUI(); } function startGame() { currentGameState = GAME_STATE_PLAYING; songSelectionInProgress = false; // Selection process is complete, game is starting gameStarted = true; gameStartTime = Date.now(); showGameplayUI(); moveScanner(); // Determine which music to play based on the selected song var musicId = 'gameMusic'; // Default music if (currentSongData === SongDatabase['Remember This']) { musicId = 'rememberThis'; } else if (currentSongData === SongDatabase['Arcade Heart']) { musicId = 'arcadeHeart'; } else if (currentSongData === SongDatabase['Runner']) { musicId = 'runner'; } LK.playMusic(musicId, { loop: false }); } function moveScanner() { if (!scanner || !gameStarted || currentGameState !== GAME_STATE_PLAYING) { return; } tween.stop(scanner); var targetY = scannerIsMovingUp ? SCANNER_Y_MIN : SCANNER_Y_MAX; tween(scanner, { y: targetY }, { duration: SCANNER_CYCLE_DURATION / 2, easing: tween.linear, onFinish: function onFinish() { scannerIsMovingUp = !scannerIsMovingUp; moveScanner(); } }); } function spawnNotesForCurrentTime(currentTime) { if (!currentSongData) { return; } currentSongData.notes.forEach(function (noteData, index) { var noteKey = index + '_' + noteData.time; var alreadySpawned = false; for (var i = 0; i < spawnedNotes.length; i++) { if (spawnedNotes[i] === noteKey) { alreadySpawned = true; break; } } if (!alreadySpawned && currentTime >= noteData.time - NOTE_SPAWN_AHEAD_MS && currentTime <= noteData.time - NOTE_SPAWN_AHEAD_MS + 100) { var calculatedY = calculateNotePosition(noteData.time); // Calculate end note Y position for hold notes var endNoteY; if (noteData.type === 'hold' && noteData.duration > 0) { var endTime = noteData.time + noteData.duration; endNoteY = calculateNotePosition(endTime); } var calculatedX = calculateZoneX(noteData.zone, calculatedY, endNoteY); // Check for overlapping notes and adjust X position if needed var attempts = 0; var maxAttempts = 10; var noteRadius = 150; // Approximate radius to avoid overlap while (attempts < maxAttempts) { var hasOverlap = false; // Check against existing active notes for (var j = 0; j < notes.length; j++) { var existingNote = notes[j]; if (!existingNote || !existingNote.active) { continue; } var distance = Math.sqrt(Math.pow(calculatedX - existingNote.x, 2) + Math.pow(calculatedY - existingNote.y, 2)); if (distance < noteRadius) { hasOverlap = true; break; } } if (!hasOverlap) { break; // Good position found } // Try a new X position within the same zone calculatedX = calculateZoneX(noteData.zone, calculatedY, endNoteY); attempts++; } var processedNoteData = { time: noteData.time, type: noteData.type, x: calculatedX, y: calculatedY, color: noteData.color, duration: noteData.duration }; var note = new Note(processedNoteData, currentTime); notes.push(note); game.addChild(note); note.spawnIn(); spawnedNotes.push(noteKey); } }); } function setupGame(songName) { LK.setScore(0); gameStarted = false; perfectCount = 0; goodCount = 0; missCount = 0; // Reset particle speed for new game baseParticleSpeed = 1; isCountdownActive = false; countdownAcceleration = 1; // Reset particle direction to downward globalParticleDirection = { x: 0, y: 1 }; targetParticleDirection = { x: 0, y: 1 }; isChangingDirection = false; lastDirectionChangeTime = Date.now(); nextDirectionChangeDelay = 15000 + Math.random() * 15000; if (scoreTxt && scoreTxt.destroy) { scoreTxt.destroy(); } scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.setText(LK.getScore()); // createZoneIndicators(); // Removed zone indicators from background if (scanner && scanner.destroy) { scanner.destroy(); } scanner = new Scanner(); scanner.y = SCANNER_Y_MAX; game.addChild(scanner); notes.forEach(function (note) { if (note && note.destroy) { note.destroy(); } }); notes = []; spawnedNotes = []; currentSongData = SongDatabase[songName]; BPM = currentSongData.bpm; BEAT_DURATION_MS = 60 / BPM * 1000; SCANNER_CYCLE_DURATION = currentSongData.scannerCycleDuration; SCANNER_HALF_CYCLE = SCANNER_CYCLE_DURATION / 2; scannerIsMovingUp = true; startCountdown(); // Reinitialize particles for proper distribution if (backgroundParticles.length === 0) { for (var i = 0; i < NUM_BACKGROUND_PARTICLES; i++) { var particle = new BackgroundParticle(); // Let init() handle the positioning backgroundParticles.push(particle); game.addChildAt(particle, 0); } } else { // Reinitialize existing particles for new distribution backgroundParticles.forEach(function (p) { p.init(); // init now handles random x and y }); } } function checkZoneHit(x, y) { var hitZone = x < GAME_WIDTH / 2 ? 'left' : 'right'; var currentTime = Date.now() - gameStartTime; for (var i = notes.length - 1; i >= 0; i--) { var note = notes[i]; if (!note || !note.active || note.isHit || note.isSpawning || !note.noteGraphics) { continue; } if (note.zone === hitZone) { var noteCoreHeight = note.noteGraphics.height; var noteCenterY = note.y; var scannerY = scanner.y; var perfectHitRadius = noteCoreHeight * PERFECT_HIT_RATIO / 2; var goodHitRadius = noteCoreHeight / 2; var perfectHitTop = noteCenterY - perfectHitRadius; var perfectHitBottom = noteCenterY + perfectHitRadius; var goodHitTop = noteCenterY - goodHitRadius; var goodHitBottom = noteCenterY + goodHitRadius; var accuracyText = null; var hitPoints = 0; var popupColor = 0xFFFFFF; if (scannerY >= perfectHitTop && scannerY <= perfectHitBottom) { accuracyText = "PERFECT"; popupColor = PERFECT_POPUP_COLOR; if (note.type === 'tap') { hitPoints = POINTS_PERFECT_TAP; } else if (note.type === 'hold') { hitPoints = POINTS_PERFECT_HOLD_START; } } else if (scannerY >= goodHitTop && scannerY <= goodHitBottom) { accuracyText = "GOOD"; popupColor = GOOD_POPUP_COLOR; if (note.type === 'tap') { hitPoints = POINTS_GOOD_TAP; } else if (note.type === 'hold') { hitPoints = POINTS_GOOD_HOLD_START; } } if (accuracyText) { note.isHit = true; showAccuracyPopup(accuracyText, note.x, note.y, popupColor); if (accuracyText === "PERFECT") { perfectCount++; } else if (accuracyText === "GOOD") { goodCount++; } if (note.type === 'tap') { note.showHitEffect(); } else if (note.type === 'hold') { note.startHoldEffect(); } if (hitPoints > 0) { LK.setScore(LK.getScore() + hitPoints); scoreTxt.setText(LK.getScore()); } break; } } } } function initializeTutorialScreen() { tutorialScreen.container = new Container(); tutorialScreen.container.visible = false; game.addChild(tutorialScreen.container); var bg = tutorialScreen.container.attachAsset('tutorialBg', { anchorX: 0, anchorY: 0 }); bg.alpha = 0.9; bg.width = GAME_WIDTH; bg.height = GAME_HEIGHT; var currentY = 80; var smallGap = 20; var mediumGap = 40; var largeGap = 60; var textBlockGap = 10; var visualOffsetY = 30; // Offset Y for visuals relative to text center var visualScale = 0.3; var noteVisualXLeft = GAME_WIDTH / 2 - 150; var noteVisualXMid = GAME_WIDTH / 2; var noteVisualXRight = GAME_WIDTH / 2 + 150; // Title var title = _createTutorialText("How to Play", 120, currentY, tutorialScreen.container, 0x00FFFF, 'center'); currentY += title.height + largeGap; // Introduction var introText = _createTutorialText("The scanner line moves up and down the screen. Notes will appear on the screen; interact with them as the scanner aligns with each note!", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'center'); currentY += introText.height + mediumGap; // Zones & Controls var zonesHeader = _createTutorialText("Play Zones & Controls", 80, currentY, tutorialScreen.container, 0xFFFF00, 'center'); currentY += zonesHeader.height + smallGap; var zonesText = _createTutorialText("The screen has a LEFT zone (Blue) and a RIGHT zone (Red). Tap ANYWHERE within the correct zone when a note aligns with the scanner line. You do NOT need to tap the note itself.", 55, currentY, tutorialScreen.container, 0xFFFFFF, 'left'); currentY += zonesText.height + mediumGap; // Tap Notes var tapHeader = _createTutorialText("Tap Notes", 80, currentY, tutorialScreen.container, 0xFFFF00, 'center'); currentY += tapHeader.height + smallGap; var tapDesc = _createTutorialText("Tap the zone once when the note aligns with the scanner.", 55, currentY, tutorialScreen.container, 0xFFFFFF, 'left'); currentY += tapDesc.height + textBlockGap; var regularTapHeader = _createTutorialText("- Regular Tap Notes:", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'left'); currentY += regularTapHeader.height + textBlockGap; var leftTapText = _createTutorialText(" Left Zone (Blue): Tap LEFT.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150); _createTutorialNoteVisual('noteCore', COLOR_LEFT_ZONE, noteVisualXLeft, currentY + visualOffsetY, visualScale, tutorialScreen.container); currentY += leftTapText.height + textBlockGap; var rightTapText = _createTutorialText(" Right Zone (Red): Tap RIGHT.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150); _createTutorialNoteVisual('noteCore', COLOR_RIGHT_ZONE, noteVisualXRight, currentY + visualOffsetY, visualScale, tutorialScreen.container); currentY += rightTapText.height + mediumGap; var syncTapHeader = _createTutorialText("- Synced Tap Notes (Pink):", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'left'); currentY += syncTapHeader.height + textBlockGap; var syncTapText = _createTutorialText(" Appear on both sides. Tap BOTH zones simultaneously.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150); currentY += syncTapText.height + mediumGap; // Space after text, before visuals var scaledVisualHeight = 300 * visualScale; // Assuming noteCore asset height is 300px var visualCenterYForTap = currentY + scaledVisualHeight / 2; _createTutorialNoteVisual('noteCore', COLOR_SYNC_TAP, noteVisualXLeft, visualCenterYForTap, visualScale, tutorialScreen.container); _createTutorialNoteVisual('noteCore', COLOR_SYNC_TAP, noteVisualXRight, visualCenterYForTap, visualScale, tutorialScreen.container); currentY += scaledVisualHeight + largeGap; // Space after visuals line // Hold Notes var holdHeader = _createTutorialText("Hold Notes", 80, currentY, tutorialScreen.container, 0xFFFF00, 'center'); currentY += holdHeader.height + smallGap; var holdDesc = _createTutorialText("Tap and HOLD for the note's trail duration. Release as the trail ends.", 55, currentY, tutorialScreen.container, 0xFFFFFF, 'left'); currentY += holdDesc.height + textBlockGap; var regularHoldHeader = _createTutorialText("- Regular Hold Notes:", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'left'); currentY += regularHoldHeader.height + textBlockGap; var leftHoldText = _createTutorialText(" Left Zone (Blue): Hold LEFT.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150); _createTutorialNoteVisual('holdNoteCore', COLOR_LEFT_ZONE, noteVisualXLeft, currentY + visualOffsetY, visualScale, tutorialScreen.container); currentY += leftHoldText.height + textBlockGap; var rightHoldText = _createTutorialText(" Right Zone (Red): Hold RIGHT.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150); _createTutorialNoteVisual('holdNoteCore', COLOR_RIGHT_ZONE, noteVisualXRight, currentY + visualOffsetY, visualScale, tutorialScreen.container); currentY += rightHoldText.height + mediumGap; var syncHoldHeader = _createTutorialText("- Synced Hold Notes (Purple):", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'left'); currentY += syncHoldHeader.height + textBlockGap; var syncHoldText = _createTutorialText(" Appear on both sides. Hold BOTH zones simultaneously.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150); currentY += syncHoldText.height + mediumGap; // Space after text, before visuals var scaledVisualHeight = 300 * visualScale; // Assuming holdNoteCore asset height is 300px var visualCenterYForHold = currentY + scaledVisualHeight / 2; _createTutorialNoteVisual('holdNoteCore', COLOR_SYNC_HOLD, noteVisualXLeft, visualCenterYForHold, visualScale, tutorialScreen.container); _createTutorialNoteVisual('holdNoteCore', COLOR_SYNC_HOLD, noteVisualXRight, visualCenterYForHold, visualScale, tutorialScreen.container); currentY += scaledVisualHeight + largeGap; // Space after visuals line // Close Button // Position close button near the bottom, ensure currentY doesn't push it off screen var closeButtonY = Math.max(currentY + mediumGap, GAME_HEIGHT - 150); tutorialScreen.closeButton = _createTutorialText("Tap to Close", 70, closeButtonY, tutorialScreen.container, 0xCCCCCC, 'center'); tutorialScreen.closeButton.interactive = true; // For clarity, though handled by game.down } function handleSongItemClick(x, y) { if (songSelectionInProgress) { return true; // Prevent new selections while one is processing } for (var i = 0; i < songSelectScreen.items.length; i++) { var item = songSelectScreen.items[i]; // Ensure item and item.scale exist before trying to use them for tweening if (!item || !item.scale) { continue; } var itemX = item.x; var itemY = item.y + songSelectScreen.scrollContainer.y; // Check if the click is within the bounds of the current item if (x >= itemX && x <= itemX + (GAME_WIDTH - 200) && y >= itemY && y <= itemY + SONG_ITEM_HEIGHT) { songSelectionInProgress = true; // Set flag // Stop any existing scale tweens on this item and reset scale before pulsing tween.stop(item.scale); item.scale.set(1.0, 1.0); // Pulse animation: scale down (shrink) tween(item.scale, { x: 0.9, y: 0.9 }, { duration: 100, // Duration of scale down easing: tween.easeOut, onFinish: function onFinish() { // Pulse animation: scale back to normal tween(item.scale, { x: 1.0, y: 1.0 }, { duration: 100, // Duration of scale back to normal easing: tween.easeIn, onFinish: function onFinish() { // Short timeout to allow pulse to be visible before screen change LK.setTimeout(function () { if (songSelectScreen.container) { songSelectScreen.container.visible = false; } setupGame(item.songName); // songSelectionInProgress will be reset by startGame or other screen transitions }, 150); // Delay before starting game setup } }); } }); return true; // Song clicked and processing started } } return false; // No song item was clicked } function initializeResultsScreen() { resultsScreen.container = new Container(); game.addChild(resultsScreen.container); resultsScreen.container.visible = false; resultsScreen.title = new Text2('Results', { size: 180, fill: 0xFFFFFF, stroke: 0x00FFFF, strokeThickness: 6 }); resultsScreen.title.anchor.set(0.5, 0.5); resultsScreen.title.x = GAME_WIDTH / 2; resultsScreen.title.y = GAME_HEIGHT / 2 - 350; resultsScreen.container.addChild(resultsScreen.title); resultsScreen.scoreText = new Text2('Final Score: 0', { size: 100, fill: 0xFFFFFF }); resultsScreen.scoreText.anchor.set(0.5, 0.5); resultsScreen.scoreText.x = GAME_WIDTH / 2; resultsScreen.scoreText.y = GAME_HEIGHT / 2 - 150; resultsScreen.container.addChild(resultsScreen.scoreText); resultsScreen.highScoreText = new Text2('High Score: 0', { size: 80, fill: 0xFFDD00 }); resultsScreen.highScoreText.anchor.set(0.5, 0.5); resultsScreen.highScoreText.x = GAME_WIDTH / 2; resultsScreen.highScoreText.y = GAME_HEIGHT / 2 - 50; resultsScreen.container.addChild(resultsScreen.highScoreText); resultsScreen.perfectText = new Text2('Perfect: 0', { size: 70, fill: 0x00FF00 }); resultsScreen.perfectText.anchor.set(0.5, 0.5); resultsScreen.perfectText.x = GAME_WIDTH / 2; resultsScreen.perfectText.y = GAME_HEIGHT / 2 + 50; resultsScreen.container.addChild(resultsScreen.perfectText); resultsScreen.goodText = new Text2('Good: 0', { size: 70, fill: 0xFFFF00 }); resultsScreen.goodText.anchor.set(0.5, 0.5); resultsScreen.goodText.x = GAME_WIDTH / 2; resultsScreen.goodText.y = GAME_HEIGHT / 2 + 130; resultsScreen.container.addChild(resultsScreen.goodText); resultsScreen.missText = new Text2('Miss: 0', { size: 70, fill: 0xFF0000 }); resultsScreen.missText.anchor.set(0.5, 0.5); resultsScreen.missText.x = GAME_WIDTH / 2; resultsScreen.missText.y = GAME_HEIGHT / 2 + 210; resultsScreen.container.addChild(resultsScreen.missText); resultsScreen.continueText = new Text2('Tap to Continue', { size: 90, fill: 0xCCCCCC }); resultsScreen.continueText.anchor.set(0.5, 0.5); resultsScreen.continueText.x = GAME_WIDTH / 2; resultsScreen.continueText.y = GAME_HEIGHT / 2 + 430; resultsScreen.container.addChild(resultsScreen.continueText); if (resultsScreen.pulseInterval) { LK.clearInterval(resultsScreen.pulseInterval); } resultsScreen.pulseInterval = LK.setInterval(function () { if (currentGameState === GAME_STATE_RESULTS && resultsScreen.continueText) { var pulseScale = resultsScreen.continueText.scale.x; var pulseDirection = resultsScreen.continueText.pulseDirection || 1; pulseScale += pulseDirection * 0.02; if (pulseScale > 1.1) { pulseScale = 1.1; pulseDirection = -1; } else if (pulseScale < 0.9) { pulseScale = 0.9; pulseDirection = 1; } resultsScreen.continueText.scale.set(pulseScale); resultsScreen.continueText.pulseDirection = pulseDirection; } }, 50); } function showTutorialScreen() { currentGameState = GAME_STATE_TUTORIAL; if (titleScreen.container) { titleScreen.container.visible = false; } if (songSelectScreen.container) { songSelectScreen.container.visible = false; } if (resultsScreen.container) { resultsScreen.container.visible = false; } if (tutorialScreen.container) { tutorialScreen.container.visible = true; } hideGameplayUI(); } initializeTitleScreen(); initializeSongSelectScreen(); initializeResultsScreen(); initializeTutorialScreen(); // Initialize the new tutorial screen for (var i = 0; i < NUM_BACKGROUND_PARTICLES; i++) { var particle = new BackgroundParticle(); particle.y = Math.random() * GAME_HEIGHT; backgroundParticles.push(particle); game.addChildAt(particle, 0); } showTitleScreen(); game.down = function (x, y, obj) { if (currentGameState === GAME_STATE_TITLE) { showSongSelectScreen(); return; } if (currentGameState === GAME_STATE_TUTORIAL) { // Check click on tutorial's close button (entire screen acts as close for simplicity) // More precise check if tutorialScreen.closeButton was an actual button object with bounds: // var cb = tutorialScreen.closeButton; // if (x >= cb.x - cb.width * cb.anchor.x && x <= cb.x + cb.width * (1-cb.anchor.x) && // y >= cb.y - cb.height * cb.anchor.y && y <= cb.y + cb.height * (1-cb.anchor.y)) { showSongSelectScreen(); // } return; } if (currentGameState === GAME_STATE_RESULTS) { showSongSelectScreen(); return; } if (currentGameState === GAME_STATE_SONG_SELECT) { // Check for tutorial button click var tb = songSelectScreen.tutorialButton; if (tb && x >= tb.x - tb.width * tb.anchor.x && x <= tb.x + tb.width * (1 - tb.anchor.x) && y >= tb.y - tb.height && y <= tb.y) { // anchor is 0.5, 1 showTutorialScreen(); return; } if (handleSongItemClick(x, y)) { return; } isDraggingSongList = true; dragStartYSongList = y; return; } if (currentGameState === GAME_STATE_PLAYING && gameStarted) { checkZoneHit(x, y); var hitZoneForDown = x < GAME_WIDTH / 2 ? 'left' : 'right'; for (var i = 0; i < notes.length; i++) { var note = notes[i]; if (!note.active || note.isSpawning || note.holdSuccessfullyCompleted || note.isMissed) { continue; } if (note.zone === hitZoneForDown && note.isHit) { if (note.type === 'hold' && !note.isHolding) { note.isHolding = true; activeHoldNotes[note.zone] = note; } } } isDragging = true; dragStartX = x; dragStartY = y; } }; game.move = function (x, y, obj) { if (currentGameState === GAME_STATE_SONG_SELECT && isDraggingSongList) { var deltaY = y - dragStartYSongList; songSelectScrollY = Math.max(0, Math.min(maxScrollY, songSelectScrollY - deltaY)); songSelectScreen.scrollContainer.y = 300 - songSelectScrollY; dragStartYSongList = y; } if (currentGameState === GAME_STATE_PLAYING && isDragging && gameStarted) {} }; game.up = function (x, y, obj) { if (currentGameState === GAME_STATE_SONG_SELECT) { isDraggingSongList = false; return; } if (currentGameState === GAME_STATE_PLAYING && gameStarted) { var releasedZone = x < GAME_WIDTH / 2 ? 'left' : 'right'; var heldNote = activeHoldNotes[releasedZone]; if (heldNote && heldNote.isHolding) { heldNote.isHolding = false; delete activeHoldNotes[releasedZone]; var currentTimeMs = Date.now() - gameStartTime; var noteExpectedEndTimeMs = heldNote.hitTime + heldNote.duration; var absoluteEndNoteY = heldNote.y + (heldNote.endNote ? heldNote.endNote.y : 0); var hitTimeCycle = heldNote.hitTime % SCANNER_CYCLE_DURATION; var noteScannerMovingUp = hitTimeCycle < SCANNER_HALF_CYCLE; var trailDirection = noteScannerMovingUp ? -1 : 1; var scannerAtEnd; if (trailDirection === -1) { scannerAtEnd = scanner.y <= absoluteEndNoteY + HIT_TOLERANCE_PX_FOR_HOLD_END && scanner.y >= absoluteEndNoteY - HIT_TOLERANCE_PX_FOR_HOLD_END / 2; } else { scannerAtEnd = scanner.y >= absoluteEndNoteY - HIT_TOLERANCE_PX_FOR_HOLD_END && scanner.y <= absoluteEndNoteY + HIT_TOLERANCE_PX_FOR_HOLD_END / 2; } var timeReachedOrPassedEnd = currentTimeMs >= noteExpectedEndTimeMs - HOLD_END_GRACE_PERIOD_MS; var timeNotTooLate = currentTimeMs <= noteExpectedEndTimeMs + HOLD_END_GRACE_PERIOD_MS + 200; if (scannerAtEnd && timeReachedOrPassedEnd && timeNotTooLate) { heldNote.completeHold(); LK.setScore(LK.getScore() + 50); scoreTxt.setText(LK.getScore()); } else { heldNote.failHold(); missCount++; } } isDragging = false; } }; game.update = function () { // Update background particles with new space travel effects backgroundParticles.forEach(function (particle) { particle.updateParticle(); }); // Handle direction changes during gameplay if (currentGameState === GAME_STATE_PLAYING && gameStarted && !isCountdownActive) { var currentTimeForDirectionChange = Date.now(); if (currentTimeForDirectionChange - lastDirectionChangeTime > nextDirectionChangeDelay) { changeParticleDirection(); } } // Handle global particle direction changes (original code) var currentTime = Date.now(); // This part is now handled by the block above for GAME_STATE_PLAYING // and the general update below might be redundant or could be simplified if only for non-playing states // For now, let's keep the existing logic structure for non-playing state direction changes or initial setup if (!isChangingDirection && currentGameState !== GAME_STATE_PLAYING && currentTime - lastDirectionChangeTime > nextDirectionChangeDelay) { changeParticleDirection(); // Call the unified function } // The following block for `if (isChangingDirection)` is now handled by `getCurrentParticleDirection` // which is called by `particle.updateParticle()`. // So, the direct manipulation of `globalParticleDirection` here might be redundant // if particles are always updating based on `getCurrentParticleDirection`. // However, `changeParticleDirection` sets `isChangingDirection = true` and `directionChangeStartTime`. // `getCurrentParticleDirection` uses these to interpolate and then resets `isChangingDirection`. // The logic seems okay as `getCurrentParticleDirection` will handle the smooth transition. if (currentGameState !== GAME_STATE_PLAYING || !gameStarted) { return; } var currentTime = Date.now() - gameStartTime; spawnNotesForCurrentTime(currentTime); for (var i = notes.length - 1; i >= 0; i--) { var note = notes[i]; if (!note) { notes.splice(i, 1); continue; } if (note.type === 'hold' && note.isHolding && note.active && !note.holdSuccessfullyCompleted && !note.isMissed) { note.updateHoldEffects(scanner.y); var currentTimeMsForUpdate = Date.now() - gameStartTime; var noteExpectedEndTimeMsForUpdate = note.hitTime + note.duration; if (currentTimeMsForUpdate > noteExpectedEndTimeMsForUpdate + HOLD_END_GRACE_PERIOD_MS + 500) { if (activeHoldNotes[note.zone] === note) { note.failHold(); delete activeHoldNotes[note.zone]; missCount++; } } } if (note.active && !note.isHit && !note.isMissed && !note.isSpawning) { var timeDiff = currentTime - note.hitTime; var scannerPassed = false; if (scannerIsMovingUp && scanner.y < note.y - 50) { scannerPassed = true; } else if (!scannerIsMovingUp && scanner.y > note.y + 50) { scannerPassed = true; } if (scannerPassed && timeDiff > 300) { note.isMissed = true; note.showMissEffect(); missCount++; } } if (!note.active) { notes.splice(i, 1); if (game.children.indexOf(note) > -1) { game.removeChild(note); } if (note.destroy) { note.destroy(); } } } if (currentSongData && currentTime > currentSongData.totalLength + 500 && currentGameState === GAME_STATE_PLAYING) { LK.stopMusic(); gameStarted = false; if (scanner) { tween.stop(scanner); } var finalScore = LK.getScore(); // --- Letter Grade Calculation (MOVED HERE) --- var totalNotes = 0; if (currentSongData && currentSongData.notes) { totalNotes = currentSongData.notes.length; } var grade = "C"; if (totalNotes > 0) { if (missCount === 0 && perfectCount === totalNotes) { grade = "S"; } else { var hitCount = perfectCount + goodCount; var ratio = hitCount / totalNotes; if (ratio >= 0.95) { grade = "A"; } else if (ratio >= 0.80) { grade = "B"; } else { grade = "C"; } } } else { grade = "-"; } var songName = null; for (var key in SongDatabase) { if (SongDatabase[key] === currentSongData) { songName = key; break; } } if (songName) { var wasUpdated = updateHighScore(songName, finalScore, grade); // Now grade is available if (wasUpdated) { // Update songSelectScreen items if they are already created if (songSelectScreen.items) { for (var j = 0; j < songSelectScreen.items.length; j++) { var item = songSelectScreen.items[j]; if (item.songName === songName) { // Assuming scoreText is the 4th child (index 3) var scoreTextDisplay = item.children[3]; if (scoreTextDisplay && scoreTextDisplay.setText) { var gradeDisplay = SongDatabase[songName].highestGrade || 'C'; scoreTextDisplay.setText('High Score: ' + SongDatabase[songName].highScore + ' | Grade: ' + gradeDisplay); } break; } } } } if (resultsScreen.highScoreText) { resultsScreen.highScoreText.setText("High Score: " + SongDatabase[songName].highScore); } } if (resultsScreen.scoreText) { resultsScreen.scoreText.setText("Final Score: " + finalScore); } if (resultsScreen.perfectText) { resultsScreen.perfectText.setText("Perfect: " + perfectCount); } if (resultsScreen.goodText) { resultsScreen.goodText.setText("Good: " + goodCount); } if (resultsScreen.missText) { resultsScreen.missText.setText("Miss: " + missCount); } if (!resultsScreen.gradeText) { resultsScreen.gradeText = new Text2('Grade: ' + grade, { size: 120, fill: 0x00FFFF }); resultsScreen.gradeText.anchor.set(0.5, 0.5); resultsScreen.gradeText.x = GAME_WIDTH / 2; resultsScreen.gradeText.y = GAME_HEIGHT / 2 + 280; resultsScreen.container.addChild(resultsScreen.gradeText); } else { resultsScreen.gradeText.setText('Grade: ' + grade); resultsScreen.gradeText.visible = true; } showResultsScreen(); } if (scanner && game.children.indexOf(scanner) > -1) { game.removeChild(scanner); game.addChild(scanner); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BackgroundParticle = Container.expand(function () {
var self = Container.call(this);
self.particleGraphics = null;
self.baseSpeed = 0;
self.initialScale = 1;
self.baseAlpha = 0.1;
self._startTwinkleAnimation = function () {
tween.stop(self, {
alpha: true
});
var currentAlpha = self.alpha;
var pulseDelta = self.baseAlpha * 0.4;
var targetMinAlpha = Math.max(0.05, self.baseAlpha - pulseDelta);
var targetMaxAlpha = Math.min(1.0, self.baseAlpha + pulseDelta);
if (targetMaxAlpha - targetMinAlpha < 0.05) {
if (self.baseAlpha < 0.15) {
targetMaxAlpha = Math.min(1.0, self.baseAlpha + 0.1);
} else if (self.baseAlpha > 0.85) {
targetMinAlpha = Math.max(0.05, self.baseAlpha - 0.1);
}
if (targetMaxAlpha - targetMinAlpha < 0.05) {
return;
}
}
var nextTargetAlpha;
if (self.alpha === self.baseAlpha || Math.abs(currentAlpha - targetMaxAlpha) < Math.abs(currentAlpha - targetMinAlpha)) {
nextTargetAlpha = targetMinAlpha;
} else {
nextTargetAlpha = targetMaxAlpha;
}
var pulseDuration = 300 + Math.random() * 400;
tween(self, {
alpha: nextTargetAlpha
}, {
duration: pulseDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self && self._startTwinkleAnimation) {
self._startTwinkleAnimation();
}
}
});
};
self.init = function () {
tween.stop(self, {
alpha: true
});
var scale = 0.312 + Math.random() * 1.248;
self.initialScale = scale;
self.scale.set(scale);
var colors = [0xff00ff, 0x00ffff, 0xffff00, 0xff0000, 0x00ff00, 0x0000ff, 0xffa500, 0xda70d6];
var color = colors[Math.floor(Math.random() * colors.length)];
if (self.particleGraphics) {
self.particleGraphics.destroy();
}
self.particleGraphics = self.attachAsset('starParticle', {
anchorX: 0.5,
anchorY: 0.5
});
self.particleGraphics.tint = color;
self.baseSpeed = (0.5 + Math.random() * 1.5) * scale;
// Distribute particles evenly across the screen
self.x = Math.random() * GAME_WIDTH;
self.y = Math.random() * GAME_HEIGHT; // Start particles throughout the screen
self.baseAlpha = 0.1 + Math.random() * 0.7;
self.alpha = self.baseAlpha;
self._startTwinkleAnimation();
};
self.updateParticle = function () {
// Get current direction (smoothly interpolated if changing)
var currentDirection = getCurrentParticleDirection();
// Calculate total speed (base * game speed * countdown acceleration)
var totalSpeed = self.baseSpeed * baseParticleSpeed * (isCountdownActive ? countdownAcceleration : 1);
// Move in the current direction - simple linear movement
self.x += currentDirection.x * totalSpeed;
self.y += currentDirection.y * totalSpeed;
// Reset particle if it goes off screen - improved distribution logic
var margin = 100;
if (self.x < -margin || self.x > GAME_WIDTH + margin || self.y < -margin || self.y > GAME_HEIGHT + margin) {
// Use weighted probability to spawn on different edges
// 60% opposite edge, 40% distributed across other edges
var spawnChoice = Math.random();
if (spawnChoice < 0.6) {
// 60% - Spawn on opposite edge (current behavior)
if (Math.abs(currentDirection.x) > Math.abs(currentDirection.y)) {
if (currentDirection.x > 0) {
self.x = -margin + Math.random() * 50;
self.y = Math.random() * GAME_HEIGHT;
} else {
self.x = GAME_WIDTH + margin - Math.random() * 50;
self.y = Math.random() * GAME_HEIGHT;
}
} else {
if (currentDirection.y > 0) {
self.x = Math.random() * GAME_WIDTH;
self.y = -margin + Math.random() * 50;
} else {
self.x = Math.random() * GAME_WIDTH;
self.y = GAME_HEIGHT + margin - Math.random() * 50;
}
}
} else {
// 40% - Spawn randomly on any edge for better distribution
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top edge
self.x = Math.random() * GAME_WIDTH;
self.y = -margin + Math.random() * 50;
break;
case 1:
// Right edge
self.x = GAME_WIDTH + margin - Math.random() * 50;
self.y = Math.random() * GAME_HEIGHT;
break;
case 2:
// Bottom edge
self.x = Math.random() * GAME_WIDTH;
self.y = GAME_HEIGHT + margin - Math.random() * 50;
break;
case 3:
// Left edge
self.x = -margin + Math.random() * 50;
self.y = Math.random() * GAME_HEIGHT;
break;
}
}
}
};
self.init();
return self;
});
var Note = Container.expand(function (noteData, spawnTime) {
var self = Container.call(this);
self.noteData = noteData;
self.type = noteData.type;
self.targetX = noteData.x;
self.targetY = noteData.y;
self.hitTime = noteData.time;
self.duration = noteData.duration || 0;
self.spawnTime = spawnTime;
self.zone = noteData.x < GAME_WIDTH / 2 ? 'left' : 'right';
if (noteData.color && noteData.color === SYNC_NOTE_COLOR) {
if (self.type === 'tap') {
self.color = COLOR_SYNC_TAP;
} else if (self.type === 'hold') {
self.color = COLOR_SYNC_HOLD;
} else {
self.color = self.zone === 'left' ? COLOR_LEFT_ZONE : COLOR_RIGHT_ZONE;
}
} else {
self.color = self.zone === 'left' ? COLOR_LEFT_ZONE : COLOR_RIGHT_ZONE;
}
self.active = true;
self.isHit = false;
self.isMissed = false;
self.isSpawning = true;
self.isHolding = false;
self.holdSuccessfullyCompleted = false;
self.holdParticles = [];
self.lastParticleEmissionTime = 0;
self.PARTICLE_EMISSION_INTERVAL = 50;
self.holdStarted = false;
self.beatPulseInterval = null;
var assetName = self.type === 'hold' ? 'holdNoteCore' : 'noteCore';
self.noteGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.noteGraphics.tint = self.color;
self._startBeatPulseAnimation = function () {
if (!self || !self.active || self.isHit || self.isMissed || self.isSpawning) {
tween.stop(self, {
scaleX: true,
scaleY: true
});
return;
}
tween.stop(self, {
scaleX: true,
scaleY: true
});
tween(self, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: BEAT_DURATION_MS * 0.2,
easing: tween.easeOut,
onFinish: function onFinish() {
if (self && self.active && !self.isHit && !self.isMissed && !self.isSpawning) {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: BEAT_DURATION_MS * 0.2,
easing: tween.easeIn
});
}
}
});
};
self._clearBeatPulseLoop = function () {
if (self.beatPulseInterval) {
LK.clearInterval(self.beatPulseInterval);
self.beatPulseInterval = null;
}
tween.stop(self, {
scaleX: true,
scaleY: true
});
};
self._initiateBeatPulseLoop = function () {
self._clearBeatPulseLoop();
if (self && self.active && !self.isHit && !self.isMissed && !self.isSpawning) {
self._startBeatPulseAnimation();
self.beatPulseInterval = LK.setInterval(function () {
if (self && self.active && !self.isHit && !self.isMissed && !self.isSpawning) {
self._startBeatPulseAnimation();
} else {
self._clearBeatPulseLoop();
}
}, BEAT_DURATION_MS);
}
};
self.x = self.targetX;
self.y = self.targetY;
self.alpha = 0;
self.scaleX = 0.1;
self.scaleY = 0.1;
self.createHoldTrail = function () {
var cycleTime = self.hitTime % SCANNER_CYCLE_DURATION;
var scannerMovingUp = cycleTime < SCANNER_HALF_CYCLE;
var direction = scannerMovingUp ? -1 : 1;
var originalRequestedDuration = self.duration;
var maxPossibleTrailPixelLength = originalRequestedDuration / SCANNER_HALF_CYCLE * PLAY_AREA_HEIGHT;
var actualTrailPixelLength = maxPossibleTrailPixelLength;
if (direction === -1) {
if (self.y - actualTrailPixelLength < SCANNER_Y_MIN) {
actualTrailPixelLength = self.y - SCANNER_Y_MIN;
}
} else {
if (self.y + actualTrailPixelLength > SCANNER_Y_MAX) {
actualTrailPixelLength = SCANNER_Y_MAX - self.y;
}
}
actualTrailPixelLength = Math.max(0, actualTrailPixelLength);
if (actualTrailPixelLength < maxPossibleTrailPixelLength) {
if (PLAY_AREA_HEIGHT > 0 && SCANNER_HALF_CYCLE > 0) {
self.duration = actualTrailPixelLength / PLAY_AREA_HEIGHT * SCANNER_HALF_CYCLE;
} else if (actualTrailPixelLength === 0) {
self.duration = 0;
}
}
self.duration = Math.max(0, self.duration);
// Create trail line first so it's below everything else
var trailLine = self.attachAsset('holdTrail', {
anchorX: 0.5,
anchorY: 0
});
trailLine.tint = self.color;
trailLine.alpha = 0.6;
trailLine.height = actualTrailPixelLength;
if (direction === -1) {
trailLine.y = -actualTrailPixelLength;
} else {
trailLine.y = 0;
}
self.holdTrails.push(trailLine);
// Move the trail to index 0 so it's below the note graphics
self.setChildIndex(trailLine, 0);
self.endNote = self.attachAsset('noteCore', {
anchorX: 0.5,
anchorY: 0.5
});
self.endNote.tint = self.color;
self.endNote.alpha = 0.8;
self.endNote.scaleX = 0.7;
self.endNote.scaleY = 0.7;
self.endNote.y = actualTrailPixelLength * direction;
self.endGlow = self.attachAsset('glowRing', {
anchorX: 0.5,
anchorY: 0.5
});
self.endGlow.tint = self.color;
self.endGlow.alpha = 0.3;
self.endGlow.scaleX = 0.5;
self.endGlow.scaleY = 0.5;
self.endGlow.y = actualTrailPixelLength * direction;
};
self.holdTrails = [];
if (self.type === 'hold' && self.duration > 0) {
self.createHoldTrail();
}
self.spawnIn = function () {
self.isSpawning = true;
tween(self, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 400,
// Increased duration for better elastic effect
easing: tween.easeElasticOut,
// Changed to elastic easing for bouncy appearance
onFinish: function onFinish() {
self.isSpawning = false;
self._initiateBeatPulseLoop();
}
});
};
self.showHitEffect = function () {
self._clearBeatPulseLoop();
LK.getSound('hitSound').play();
self.explodeIntoParticles();
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.active = false;
self._clearBeatPulseLoop();
}
});
};
self.startHoldEffect = function () {
self._clearBeatPulseLoop();
LK.getSound('hitSound').play();
tween(self.noteGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(self.noteGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
self.showMissEffect = function () {
self._clearBeatPulseLoop();
LK.getSound('missSound').play();
// First change color to red
tween(self.noteGraphics, {
tint: 0xff0000
}, {
duration: 150,
onFinish: function onFinish() {
// Then collapse inward with elastic ease-in for a crushing effect
tween(self, {
alpha: 0,
scaleX: 0,
scaleY: 0
}, {
duration: 500,
// Slightly longer for dramatic effect
easing: tween.easeElasticIn,
// Elastic ease-in for collapsing effect
onFinish: function onFinish() {
self.active = false;
self._clearBeatPulseLoop();
}
});
}
});
};
self.explodeIntoParticles = function () {
var noteScale = 1.2; // Base scale relative to noteCore (300px)
// Stage 1: Initial Flash (0-200ms)
var flash = game.attachAsset('supernovaFlash', {
anchorX: 0.5,
anchorY: 0.5
});
flash.tint = 0xFFFFFF;
flash.x = self.x;
flash.y = self.y;
flash.alpha = 0;
flash.scale.set(0.1 * noteScale);
tween(flash, {
alpha: 1,
scaleX: 2.8 * noteScale,
scaleY: 2.8 * noteScale
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(flash, {
alpha: 0
}, {
duration: 350,
onFinish: function onFinish() {
if (flash && flash.destroy) {
flash.destroy();
}
}
});
}
});
// Stage 2: Shockwave (100-600ms)
LK.setTimeout(function () {
var shockwave = game.attachAsset('supernovaShockwave', {
anchorX: 0.5,
anchorY: 0.5
});
shockwave.tint = 0x00FFFF;
shockwave.x = self.x;
shockwave.y = self.y;
shockwave.alpha = 1;
shockwave.scale.set(0.2 * noteScale);
tween(shockwave, {
scaleX: 5.0 * noteScale,
scaleY: 5.0 * noteScale,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
if (shockwave && shockwave.destroy) {
shockwave.destroy();
}
}
});
}, 100);
// Stage 3: Core Particles (50-800ms)
var coreParticleCount = 15;
for (var i = 0; i < coreParticleCount; i++) {
(function (index) {
LK.setTimeout(function () {
var coreAsset = Math.random() < 0.5 ? 'supernovaCoreParticle' : 'supernovaCoreParticle2';
var particle = game.attachAsset(coreAsset, {
anchorX: 0.5,
anchorY: 0.5
});
particle.tint = Math.random() < 0.5 ? 0xFFFFFF : 0xFFFF88;
particle.x = self.x;
particle.y = self.y;
var angle = index / coreParticleCount * Math.PI * 2 + (Math.random() - 0.5) * 0.5;
var speed = 200 + Math.random() * 150;
var targetX = self.x + Math.cos(angle) * speed;
var targetY = self.y + Math.sin(angle) * speed;
var finalScale = (0.5 + Math.random() * 0.4) * noteScale;
particle.scale.set(0.2 * noteScale);
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: finalScale,
scaleY: finalScale
}, {
duration: 900,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle && particle.destroy) {
particle.destroy();
}
}
});
}, 50 + Math.random() * 100);
})(i);
}
// Stage 4: Nebula Trails (200-1200ms)
var nebulaCount = 20;
for (var j = 0; j < nebulaCount; j++) {
(function (index) {
LK.setTimeout(function () {
var nebulaAssets = ['supernovaNebulaTrail', 'supernovaNebulaTrail2', 'supernovaNebulaTrail3'];
var nebulaAsset = nebulaAssets[Math.floor(Math.random() * nebulaAssets.length)];
var particle = game.attachAsset(nebulaAsset, {
anchorX: 0.5,
anchorY: 0.5
});
var colors = [0x8844FF, 0xFF44AA, 0x4488FF, 0xAA44FF];
particle.tint = colors[Math.floor(Math.random() * colors.length)];
particle.x = self.x + (Math.random() - 0.5) * 40;
particle.y = self.y + (Math.random() - 0.5) * 40;
particle.alpha = 0.8 + Math.random() * 0.3;
var angle = Math.random() * Math.PI * 2;
var speed = 80 + Math.random() * 120;
var targetX = self.x + Math.cos(angle) * speed;
var targetY = self.y + Math.sin(angle) * speed;
var finalScale = (0.4 + Math.random() * 0.3) * noteScale;
particle.scale.set(0.2 * noteScale);
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: finalScale,
scaleY: finalScale,
rotation: Math.random() * Math.PI * 2
}, {
duration: 1300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle && particle.destroy) {
particle.destroy();
}
}
});
}, 200 + Math.random() * 200);
})(j);
}
// Stage 5: Stellar Debris (150-1000ms)
var debrisCount = 12;
for (var k = 0; k < debrisCount; k++) {
(function (index) {
LK.setTimeout(function () {
var debrisAsset = Math.random() < 0.5 ? 'supernovaStellarDebris' : 'supernovaStellarDebris2';
var particle = game.attachAsset(debrisAsset, {
anchorX: 0.5,
anchorY: 0.5
});
var colors = [0xFF4400, 0xFF6600, 0xFFAA00, 0xFFFFFF];
particle.tint = colors[Math.floor(Math.random() * colors.length)];
particle.x = self.x;
particle.y = self.y;
var angle = Math.random() * Math.PI * 2;
var speed = 120 + Math.random() * 100;
var targetX = self.x + Math.cos(angle) * speed;
var targetY = self.y + Math.sin(angle) * speed;
var finalScale = (0.25 + Math.random() * 0.25) * noteScale;
particle.scale.set(0.10 * noteScale);
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: finalScale,
scaleY: finalScale,
rotation: Math.random() * Math.PI * 4 // Multiple rotations
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle && particle.destroy) {
particle.destroy();
}
}
});
}, 150 + Math.random() * 150);
})(k);
}
// Stage 6: Energy Sparks (100-700ms)
var sparkCount = 25;
for (var l = 0; l < sparkCount; l++) {
(function (index) {
LK.setTimeout(function () {
var sparkAsset = Math.random() < 0.5 ? 'supernovaEnergySpark' : 'supernovaEnergySpark2';
var particle = game.attachAsset(sparkAsset, {
anchorX: 0.5,
anchorY: 0.5
});
particle.tint = Math.random() < 0.5 ? 0x00FFFF : 0x0088FF;
particle.x = self.x + (Math.random() - 0.5) * 20;
particle.y = self.y + (Math.random() - 0.5) * 20;
var angle = Math.random() * Math.PI * 2;
var speed = 180 + Math.random() * 220;
var targetX = self.x + Math.cos(angle) * speed;
var targetY = self.y + Math.sin(angle) * speed;
var finalScale = (0.2 + Math.random() * 0.2) * noteScale;
particle.scale.set(0.1 * noteScale);
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: finalScale,
scaleY: finalScale
}, {
duration: 900,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle && particle.destroy) {
particle.destroy();
}
}
});
}, 100 + Math.random() * 100);
})(l);
}
// Stage 7: Afterglow (300-1500ms)
LK.setTimeout(function () {
var afterglow = game.attachAsset('supernovaAfterglow', {
anchorX: 0.5,
anchorY: 0.5
});
afterglow.tint = 0xFF6600;
afterglow.x = self.x;
afterglow.y = self.y;
afterglow.alpha = 0.4;
afterglow.scale.set(1.2 * noteScale);
tween(afterglow, {
alpha: 0,
scaleX: 3.0 * noteScale,
scaleY: 3.0 * noteScale
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
if (afterglow && afterglow.destroy) {
afterglow.destroy();
}
}
});
}, 400);
};
self.explodeEndNoteParticles = function () {
if (!self.endNote) {
return;
}
var noteScale = 1.2; // Same scale as main note
var endNoteGlobalX = self.x;
var endNoteGlobalY = self.y + self.endNote.y;
// Stage 1: Initial Flash (0-200ms)
var flash = game.attachAsset('supernovaFlash', {
anchorX: 0.5,
anchorY: 0.5
});
flash.tint = 0xFFFFFF;
flash.x = endNoteGlobalX;
flash.y = endNoteGlobalY;
flash.alpha = 0;
flash.scale.set(0.1 * noteScale);
tween(flash, {
alpha: 1,
scaleX: 2.5 * noteScale,
scaleY: 2.5 * noteScale
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(flash, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (flash && flash.destroy) {
flash.destroy();
}
}
});
}
});
// Stage 2: Shockwave (100-600ms)
LK.setTimeout(function () {
var shockwave = game.attachAsset('supernovaShockwave', {
anchorX: 0.5,
anchorY: 0.5
});
shockwave.tint = 0x00FFFF;
shockwave.x = endNoteGlobalX;
shockwave.y = endNoteGlobalY;
shockwave.alpha = 0.9;
shockwave.scale.set(0.2 * noteScale);
tween(shockwave, {
scaleX: 5.0 * noteScale,
scaleY: 5.0 * noteScale,
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
if (shockwave && shockwave.destroy) {
shockwave.destroy();
}
}
});
}, 100);
// Stage 3: Core Particles (50-800ms)
var coreParticleCount = 15;
for (var i = 0; i < coreParticleCount; i++) {
(function (index) {
LK.setTimeout(function () {
var coreAsset = Math.random() < 0.5 ? 'supernovaCoreParticle' : 'supernovaCoreParticle2';
var particle = game.attachAsset(coreAsset, {
anchorX: 0.5,
anchorY: 0.5
});
particle.tint = Math.random() < 0.5 ? 0xFFFFFF : 0xFFFF88;
particle.x = endNoteGlobalX;
particle.y = endNoteGlobalY;
var angle = index / coreParticleCount * Math.PI * 2 + (Math.random() - 0.5) * 0.5;
var speed = 200 + Math.random() * 150;
var targetX = endNoteGlobalX + Math.cos(angle) * speed;
var targetY = endNoteGlobalY + Math.sin(angle) * speed;
var finalScale = (0.3 + Math.random() * 0.4) * noteScale;
particle.scale.set(0.1 * noteScale);
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: finalScale,
scaleY: finalScale
}, {
duration: 750,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle && particle.destroy) {
particle.destroy();
}
}
});
}, 50 + Math.random() * 100);
})(i);
}
// Stage 4: Nebula Trails (200-1200ms)
var nebulaCount = 20;
for (var j = 0; j < nebulaCount; j++) {
(function (index) {
LK.setTimeout(function () {
var nebulaAssets = ['supernovaNebulaTrail', 'supernovaNebulaTrail2', 'supernovaNebulaTrail3'];
var nebulaAsset = nebulaAssets[Math.floor(Math.random() * nebulaAssets.length)];
var particle = game.attachAsset(nebulaAsset, {
anchorX: 0.5,
anchorY: 0.5
});
var colors = [0x8844FF, 0xFF44AA, 0x4488FF, 0xAA44FF];
particle.tint = colors[Math.floor(Math.random() * colors.length)];
particle.x = endNoteGlobalX + (Math.random() - 0.5) * 40;
particle.y = endNoteGlobalY + (Math.random() - 0.5) * 40;
particle.alpha = 0.7 + Math.random() * 0.3;
var angle = Math.random() * Math.PI * 2;
var speed = 80 + Math.random() * 120;
var targetX = endNoteGlobalX + Math.cos(angle) * speed;
var targetY = endNoteGlobalY + Math.sin(angle) * speed;
var finalScale = (0.2 + Math.random() * 0.3) * noteScale;
particle.scale.set(0.1 * noteScale);
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: finalScale,
scaleY: finalScale,
rotation: Math.random() * Math.PI * 2
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle && particle.destroy) {
particle.destroy();
}
}
});
}, 200 + Math.random() * 200);
})(j);
}
// Stage 5: Stellar Debris (150-1000ms)
var debrisCount = 12;
for (var k = 0; k < debrisCount; k++) {
(function (index) {
LK.setTimeout(function () {
var debrisAsset = Math.random() < 0.5 ? 'supernovaStellarDebris' : 'supernovaStellarDebris2';
var particle = game.attachAsset(debrisAsset, {
anchorX: 0.5,
anchorY: 0.5
});
var colors = [0xFF4400, 0xFF6600, 0xFFAA00, 0xFFFFFF];
particle.tint = colors[Math.floor(Math.random() * colors.length)];
particle.x = endNoteGlobalX;
particle.y = endNoteGlobalY;
var angle = Math.random() * Math.PI * 2;
var speed = 120 + Math.random() * 100;
var targetX = endNoteGlobalX + Math.cos(angle) * speed;
var targetY = endNoteGlobalY + Math.sin(angle) * speed;
var finalScale = (0.15 + Math.random() * 0.25) * noteScale;
particle.scale.set(0.05 * noteScale);
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: finalScale,
scaleY: finalScale,
rotation: Math.random() * Math.PI * 4
}, {
duration: 850,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle && particle.destroy) {
particle.destroy();
}
}
});
}, 150 + Math.random() * 150);
})(k);
}
// Stage 6: Energy Sparks (100-700ms)
var sparkCount = 25;
for (var l = 0; l < sparkCount; l++) {
(function (index) {
LK.setTimeout(function () {
var sparkAsset = Math.random() < 0.5 ? 'supernovaEnergySpark' : 'supernovaEnergySpark2';
var particle = game.attachAsset(sparkAsset, {
anchorX: 0.5,
anchorY: 0.5
});
particle.tint = Math.random() < 0.5 ? 0x00FFFF : 0x0088FF;
particle.x = endNoteGlobalX + (Math.random() - 0.5) * 20;
particle.y = endNoteGlobalY + (Math.random() - 0.5) * 20;
var angle = Math.random() * Math.PI * 2;
var speed = 180 + Math.random() * 220;
var targetX = endNoteGlobalX + Math.cos(angle) * speed;
var targetY = endNoteGlobalY + Math.sin(angle) * speed;
var finalScale = (0.1 + Math.random() * 0.2) * noteScale;
particle.scale.set(0.05 * noteScale);
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: finalScale,
scaleY: finalScale
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle && particle.destroy) {
particle.destroy();
}
}
});
}, 100 + Math.random() * 100);
})(l);
}
// Stage 7: Afterglow (300-1500ms)
LK.setTimeout(function () {
var afterglow = game.attachAsset('supernovaAfterglow', {
anchorX: 0.5,
anchorY: 0.5
});
afterglow.tint = 0xFF6600;
afterglow.x = endNoteGlobalX;
afterglow.y = endNoteGlobalY;
afterglow.alpha = 0.4;
afterglow.scale.set(1.2 * noteScale);
tween(afterglow, {
alpha: 0,
scaleX: 2.0 * noteScale,
scaleY: 2.0 * noteScale
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
if (afterglow && afterglow.destroy) {
afterglow.destroy();
}
}
});
}, 300);
};
self.updateHoldEffects = function (scannerCurrentY) {
if (self.type === 'hold' && self.isHolding && self.active && !self.holdSuccessfullyCompleted && !self.isMissed) {
var currentTime = Date.now();
if (currentTime - self.lastParticleEmissionTime > self.PARTICLE_EMISSION_INTERVAL) {
self.lastParticleEmissionTime = currentTime;
var trailStartY = self.y;
var trailEndY = self.y + (self.endNote ? self.endNote.y : 0);
var scannerIsOverTrail = self.endNote && scannerCurrentY >= Math.min(trailStartY, trailEndY) && scannerCurrentY <= Math.max(trailStartY, trailEndY);
if (scannerIsOverTrail) {
var particle = game.attachAsset('holdConnectionParticle', {
anchorX: 0.5,
anchorY: 0.5
});
particle.x = self.x;
particle.y = scannerCurrentY;
particle.tint = self.color;
particle.alpha = 0.8;
self.holdParticles.push(particle);
tween(particle, {
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle && particle.destroy) {
particle.destroy();
}
var index = self.holdParticles.indexOf(particle);
if (index > -1) {
self.holdParticles.splice(index, 1);
}
}
});
}
}
}
};
self.cleanupHoldVisuals = function () {
self.holdParticles.forEach(function (p) {
if (p && p.destroy) {
p.destroy();
}
});
self.holdParticles = [];
if (self.endNote && self.endNote.destroy) {
self.endNote.destroy();
}
if (self.endGlow && self.endGlow.destroy) {
self.endGlow.destroy();
}
self.endNote = null;
self.endGlow = null;
self.holdTrails.forEach(function (trail) {
if (trail && trail.destroy) {
trail.destroy();
}
});
self.holdTrails = [];
};
self.completeHold = function () {
if (self.holdSuccessfullyCompleted || self.isMissed) {
return;
}
self._clearBeatPulseLoop();
self.holdSuccessfullyCompleted = true;
self.isHolding = false;
self.explodeIntoParticles();
if (self.type === 'hold') {
self.explodeEndNoteParticles();
}
self.cleanupHoldVisuals();
tween(self, {
alpha: 0
}, {
duration: 100,
delay: 100,
onFinish: function onFinish() {
self.active = false;
self._clearBeatPulseLoop();
}
});
};
self.failHold = function () {
if (self.isMissed || self.holdSuccessfullyCompleted) {
return;
}
self._clearBeatPulseLoop();
self.isMissed = true;
self.isHolding = false;
self.showMissEffect();
self.cleanupHoldVisuals();
};
return self;
});
var Scanner = Container.expand(function () {
var self = Container.call(this);
self.glow = self.attachAsset('scannerGlow', {
anchorX: 0,
anchorY: 0.5
});
self.glow.alpha = 0.2;
self.line = self.attachAsset('scannerLine', {
anchorX: 0,
anchorY: 0.5
});
self.x = 0;
self.isMovingUp = true;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Add these global variables (replace the previous ones)
var globalParticleDirection = {
x: 0,
y: 1
}; // Start moving downward
var targetParticleDirection = {
x: 0,
y: 1
};
var directionChangeStartTime = 0;
var directionChangeDuration = 1000; // 1 second
var isChangingDirection = false;
var lastDirectionChangeTime = 0;
var nextDirectionChangeDelay = 15000 + Math.random() * 15000; // 15-30 seconds
var baseParticleSpeed = 1; // Base speed multiplier
var countdownAcceleration = 1; // Separate from base speed
var isCountdownActive = false;
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var SAFETY_MARGIN_TOP_PERCENT = 0.05;
var SAFETY_MARGIN_BOTTOM_PERCENT = 0.15;
var SAFETY_MARGIN_SIDES_PERCENT = 0.10;
var BPM = 120;
var BEAT_DURATION_MS = 60 / BPM * 1000;
var SCANNER_Y_MIN = GAME_HEIGHT * SAFETY_MARGIN_TOP_PERCENT;
var SCANNER_Y_MAX = GAME_HEIGHT * (1 - SAFETY_MARGIN_BOTTOM_PERCENT);
var PLAY_AREA_HEIGHT = SCANNER_Y_MAX - SCANNER_Y_MIN;
var NOTE_SPAWN_AHEAD_MS = 800;
var PERFECT_HIT_RATIO = 0.4;
var POINTS_PERFECT_TAP = 30;
var POINTS_GOOD_TAP = 15;
var POINTS_PERFECT_HOLD_START = 10;
var POINTS_GOOD_HOLD_START = 5;
var ACCURACY_POPUP_DURATION = 750;
var ACCURACY_POPUP_Y_OFFSET = -100;
var ACCURACY_POPUP_FONT_SIZE = 80;
var PERFECT_POPUP_COLOR = 0x00FF00;
var GOOD_POPUP_COLOR = 0xFFFF00;
var SCANNER_CYCLE_DURATION = 4000;
var SCANNER_HALF_CYCLE = SCANNER_CYCLE_DURATION / 2;
var HIT_TOLERANCE_PX_FOR_HOLD_END = 100;
var HOLD_END_GRACE_PERIOD_MS = 250;
var GAME_STATE_TITLE = 'title';
var GAME_STATE_SONG_SELECT = 'songSelect';
var GAME_STATE_PLAYING = 'playing';
var GAME_STATE_RESULTS = 'results';
var GAME_STATE_TUTORIAL = 'tutorial'; // New game state for the tutorial
var currentGameState = GAME_STATE_TITLE;
var resultsScreen = {};
var tutorialScreen = {}; // Holds tutorial screen elements
var activeHoldNotes = {};
var scoreTxt;
var countdownTxt;
var perfectCount = 0;
var goodCount = 0;
var missCount = 0;
var scanner;
var scannerIsMovingUp = true;
var gameStartTime;
var gameStarted = false;
var notes = [];
var currentSongData;
var spawnedNotes = [];
var leftZone, rightZone;
var isDragging = false;
var dragStartX, dragStartY;
var currentTrail = [];
var backgroundParticles = [];
var NUM_BACKGROUND_PARTICLES = 200;
var titleScreen = {};
var songSelectScreen = {};
var songSelectScrollY = 0;
var maxScrollY = 0;
var isDraggingSongList = false;
var dragStartYSongList = 0;
var songSelectionInProgress = false; // Flag to prevent multiple song selections simultaneously
var SONG_ITEM_HEIGHT = 330;
var COLOR_LEFT_ZONE = 0x0077FF;
var COLOR_RIGHT_ZONE = 0xFF3333;
var COLOR_SYNC_TAP = 0xFF69B4;
var COLOR_SYNC_HOLD = 0x9370DB;
var SYNC_NOTE_COLOR = 0xFFA500;
// Helper function to get current particle direction with smooth interpolation
function getCurrentParticleDirection() {
if (!isChangingDirection) {
return globalParticleDirection;
}
var currentTime = Date.now();
var elapsed = currentTime - directionChangeStartTime;
var progress = Math.min(elapsed / directionChangeDuration, 1);
// Smooth easing
var easedProgress = progress * progress * (3 - 2 * progress); // Smoothstep
// Interpolate between current and target direction
var lerpX = globalParticleDirection.x + (targetParticleDirection.x - globalParticleDirection.x) * easedProgress;
var lerpY = globalParticleDirection.y + (targetParticleDirection.y - globalParticleDirection.y) * easedProgress;
// Normalize the direction
var length = Math.sqrt(lerpX * lerpX + lerpY * lerpY);
if (length > 0) {
lerpX /= length;
lerpY /= length;
}
// Check if transition is complete
if (progress >= 1) {
isChangingDirection = false;
globalParticleDirection.x = targetParticleDirection.x;
globalParticleDirection.y = targetParticleDirection.y;
lastDirectionChangeTime = currentTime;
nextDirectionChangeDelay = 15000 + Math.random() * 15000; // 15-30 seconds
}
return {
x: lerpX,
y: lerpY
};
}
// Function to initiate a direction change
function changeParticleDirection() {
if (isChangingDirection) {
return;
}
// Calculate the turn direction
var currentAngle = Math.atan2(globalParticleDirection.y, globalParticleDirection.x);
var angleChange = Math.PI / 4 + Math.random() * (Math.PI / 4); // 45-90 degrees
if (Math.random() < 0.5) {
angleChange = -angleChange;
}
var newAngle = currentAngle + angleChange;
targetParticleDirection.x = Math.cos(newAngle);
targetParticleDirection.y = Math.sin(newAngle);
// Predict which corner will become bare and pre-fill it
// var turnDirection = angleChange; // Positive = turning counter-clockwise, Negative = turning clockwise // Not directly used but good for understanding
// Determine which corner will be "left behind" by the turn
var bareCornerX, bareCornerY;
// var currentDir = globalParticleDirection; // Not strictly needed as newDir determines flow out
var newDir = targetParticleDirection;
// The bare corner is opposite to where particles are flowing towards *after* the turn.
// Example: If newDir is bottom-right (x > 0, y > 0), particles flow towards bottom-right.
// The corner "emptied" or "left behind" will be the top-left (0,0).
if (newDir.x > 0 && newDir.y > 0) {
// Flowing toward bottom-right
bareCornerX = 0; // Top-left will be bare
bareCornerY = 0;
} else if (newDir.x < 0 && newDir.y > 0) {
// Flowing toward bottom-left
bareCornerX = GAME_WIDTH; // Top-right will be bare
bareCornerY = 0;
} else if (newDir.x < 0 && newDir.y < 0) {
// Flowing toward top-left
bareCornerX = GAME_WIDTH; // Bottom-right will be bare
bareCornerY = GAME_HEIGHT;
} else {
// Flowing toward top-right (newDir.x > 0 && newDir.y < 0)
bareCornerX = 0; // Bottom-left will be bare
bareCornerY = GAME_HEIGHT;
}
// Spawn particles in the predicted bare corner area
var cornerSize = Math.min(GAME_WIDTH, GAME_HEIGHT) * 0.3; // 30% of screen from corner
for (var i = 0; i < 15; i++) {
var extraParticle = new BackgroundParticle();
// Position in the bare corner area
if (bareCornerX === 0) {
extraParticle.x = Math.random() * cornerSize;
} else {
extraParticle.x = GAME_WIDTH - Math.random() * cornerSize;
}
if (bareCornerY === 0) {
extraParticle.y = Math.random() * cornerSize;
} else {
extraParticle.y = GAME_HEIGHT - Math.random() * cornerSize;
}
backgroundParticles.push(extraParticle);
game.addChildAt(extraParticle, 0); // Add behind other game elements
}
isChangingDirection = true;
directionChangeStartTime = Date.now();
}
var PatternTemplates = {
tapLeft: function tapLeft(startTime) {
return [{
time: startTime,
type: 'tap',
zone: 'left'
}];
},
tapRight: function tapRight(startTime) {
return [{
time: startTime,
type: 'tap',
zone: 'right'
}];
},
syncTap: function syncTap(startTime) {
return [{
time: startTime,
type: 'tap',
zone: 'left'
}, {
time: startTime,
type: 'tap',
zone: 'right'
}];
},
leftRightTaps: function leftRightTaps(startTime, spacing) {
spacing = spacing || 500;
return [{
time: startTime,
type: 'tap',
zone: 'left'
}, {
time: startTime + spacing,
type: 'tap',
zone: 'right'
}];
},
rightLeftTaps: function rightLeftTaps(startTime, spacing) {
spacing = spacing || 500;
return [{
time: startTime,
type: 'tap',
zone: 'right'
}, {
time: startTime + spacing,
type: 'tap',
zone: 'left'
}];
},
holdLeft: function holdLeft(startTime, duration) {
duration = duration || 1000;
return [{
time: startTime,
type: 'hold',
zone: 'left',
duration: duration
}];
},
holdRight: function holdRight(startTime, duration) {
duration = duration || 1000;
return [{
time: startTime,
type: 'hold',
zone: 'right',
duration: duration
}];
},
syncHold: function syncHold(startTime, duration) {
duration = duration || 1000;
return [{
time: startTime,
type: 'hold',
zone: 'left',
duration: duration
}, {
time: startTime,
type: 'hold',
zone: 'right',
duration: duration
}];
},
tripletTaps: function tripletTaps(startTime, zone, spacing) {
spacing = spacing || 167;
return [{
time: startTime,
type: 'tap',
zone: zone
}, {
time: startTime + spacing,
type: 'tap',
zone: zone
}, {
time: startTime + spacing * 2,
type: 'tap',
zone: zone
}];
},
alternatingTriplets: function alternatingTriplets(startTime, spacing) {
spacing = spacing || 167;
return [{
time: startTime,
type: 'tap',
zone: 'left'
}, {
time: startTime + spacing,
type: 'tap',
zone: 'right'
}, {
time: startTime + spacing * 2,
type: 'tap',
zone: 'left'
}];
},
buildUp: function buildUp(startTime) {
return [{
time: startTime,
type: 'tap',
zone: 'left'
}, {
time: startTime + 250,
type: 'tap',
zone: 'right'
}, {
time: startTime + 500,
type: 'tap',
zone: 'left'
}, {
time: startTime + 625,
type: 'tap',
zone: 'right'
}, {
time: startTime + 750,
type: 'tap',
zone: 'left'
}, {
time: startTime + 875,
type: 'tap',
zone: 'right'
}];
}
};
var SongGenerator = {
generateSong: function generateSong(config) {
var notes = [];
var totalLength = config.totalLength || 202136;
var startTime = config.startDelay || 2000;
notes = this.generateZoneAwareSong(startTime, totalLength);
notes.sort(function (a, b) {
return a.time - b.time;
});
return notes;
},
generateZoneAwareSong: function generateZoneAwareSong(startTime, songTotalLength) {
var notes = [];
var currentTime = startTime;
var zoneFreeTime = {
left: startTime,
right: startTime
};
var MIN_SAME_ZONE_SPACING = 400;
var MIN_DIFFERENT_ZONE_SPACING = 200;
var MIN_SYNC_SPACING = 1000;
var lastSyncTime = startTime - MIN_SYNC_SPACING;
var sections = [{
start: 0,
end: 16000,
complexity: 'simple'
}, {
start: 16000,
end: 48000,
complexity: 'medium'
}, {
start: 48000,
end: 72000,
complexity: 'medium'
}, {
start: 72000,
end: 104000,
complexity: 'medium'
}, {
start: 104000,
end: 128000,
complexity: 'complex'
}, {
start: 128000,
end: 160000,
complexity: 'medium'
}, {
start: 160000,
end: 184000,
complexity: 'complex'
}, {
start: 184000,
end: songTotalLength,
complexity: 'simple'
}];
for (var s = 0; s < sections.length; s++) {
var section = sections[s];
var sectionStartTime = startTime + section.start;
var sectionEndTime = startTime + section.end;
if (sectionEndTime > startTime + songTotalLength) {
sectionEndTime = startTime + songTotalLength;
}
if (sectionStartTime >= sectionEndTime) {
continue;
}
currentTime = Math.max(currentTime, sectionStartTime);
while (currentTime < sectionEndTime - 1000) {
var pattern = this.selectPattern(section.complexity, zoneFreeTime, currentTime, lastSyncTime);
var patternResult = this.placePattern(pattern, currentTime, zoneFreeTime, MIN_SAME_ZONE_SPACING, MIN_DIFFERENT_ZONE_SPACING, sectionEndTime);
if (patternResult.notes.length > 0) {
var allNotesFit = true;
for (var ni = 0; ni < patternResult.notes.length; ni++) {
if (patternResult.notes[ni].time + (patternResult.notes[ni].duration || 0) > sectionEndTime - 200) {
allNotesFit = false;
break;
}
}
if (allNotesFit) {
notes = notes.concat(patternResult.notes);
currentTime = patternResult.nextTime;
if (pattern.type === 'sync' || pattern.type === 'syncHold') {
lastSyncTime = patternResult.notes[0].time;
}
} else {
currentTime += 300;
}
} else {
currentTime += 300;
}
if (currentTime >= sectionEndTime - 1000) {
break;
}
}
}
return notes;
},
selectPattern: function selectPattern(complexity, zoneFreeTime, currentTime, lastSyncTime) {
var patterns = [];
var MIN_SYNC_SPACING_FOR_SELECTION = 1000;
if (complexity === 'simple') {
patterns = [{
type: 'single',
zone: 'left',
duration: 800
}, {
type: 'single',
zone: 'right',
duration: 800
}, {
type: 'rest',
duration: 1200
}, {
type: 'rest',
duration: 1200
}];
if (currentTime - lastSyncTime >= MIN_SYNC_SPACING_FOR_SELECTION + 200) {
patterns.push({
type: 'sync',
duration: 1000
});
}
} else if (complexity === 'medium') {
patterns = [{
type: 'hold',
zone: 'right',
holdDuration: 1000,
duration: 700
}, {
type: 'single',
zone: 'left',
duration: 600
}, {
type: 'single',
zone: 'right',
duration: 600
}, {
type: 'single',
zone: 'left',
duration: 600
}, {
type: 'single',
zone: 'right',
duration: 600
}, {
type: 'alternating',
duration: 750
}, {
type: 'rest',
duration: 1000
}];
if (currentTime - lastSyncTime >= MIN_SYNC_SPACING_FOR_SELECTION) {
patterns.push({
type: 'sync',
duration: 800
});
patterns.push({
type: 'sync',
duration: 800
});
}
} else {
patterns = [{
type: 'hold',
zone: 'right',
holdDuration: 1200,
duration: 800
}, {
type: 'alternating',
duration: 800
}, {
type: 'alternating',
duration: 800
}, {
type: 'single',
zone: 'left',
duration: 700
}, {
type: 'single',
zone: 'right',
duration: 700
}, {
type: 'single',
zone: 'left',
duration: 700
}, {
type: 'single',
zone: 'right',
duration: 700
}];
if (currentTime - lastSyncTime >= MIN_SYNC_SPACING_FOR_SELECTION - 200) {
patterns.push({
type: 'sync',
duration: 600
});
patterns.push({
type: 'sync',
duration: 600
});
patterns.push({
type: 'syncHold',
holdDuration: 1200,
duration: 900
});
}
}
return patterns[Math.floor(Math.random() * patterns.length)];
},
placePattern: function placePattern(pattern, requestedTime, zoneFreeTime, minSameZoneSpacing, minDiffZoneSpacing, sectionEndTime) {
var notes = [];
var earliestTime = requestedTime;
var nextTimeAdvance = pattern.duration || 500;
if (pattern.type === 'single') {
earliestTime = Math.max(requestedTime, zoneFreeTime[pattern.zone]);
if (earliestTime + (pattern.duration || 0) < sectionEndTime) {
notes.push({
time: earliestTime,
type: 'tap',
zone: pattern.zone
});
zoneFreeTime[pattern.zone] = earliestTime + minSameZoneSpacing;
return {
notes: notes,
nextTime: earliestTime + nextTimeAdvance
};
}
} else if (pattern.type === 'sync') {
earliestTime = Math.max(requestedTime, zoneFreeTime.left, zoneFreeTime.right);
if (earliestTime + (pattern.duration || 0) < sectionEndTime) {
notes.push({
time: earliestTime,
type: 'tap',
zone: 'left',
color: SYNC_NOTE_COLOR
});
notes.push({
time: earliestTime,
type: 'tap',
zone: 'right',
color: SYNC_NOTE_COLOR
});
zoneFreeTime.left = earliestTime + minSameZoneSpacing;
zoneFreeTime.right = earliestTime + minSameZoneSpacing;
return {
notes: notes,
nextTime: earliestTime + nextTimeAdvance
};
}
} else if (pattern.type === 'alternating') {
var firstZone = Math.random() < 0.5 ? 'left' : 'right';
var secondZone = firstZone === 'left' ? 'right' : 'left';
var t1 = Math.max(requestedTime, zoneFreeTime[firstZone]);
var t2 = Math.max(t1 + minDiffZoneSpacing, zoneFreeTime[secondZone]);
if (t2 + (pattern.duration || 0) - (t2 - t1) < sectionEndTime) {
notes.push({
time: t1,
type: 'tap',
zone: firstZone
});
notes.push({
time: t2,
type: 'tap',
zone: secondZone
});
zoneFreeTime[firstZone] = t1 + minSameZoneSpacing;
zoneFreeTime[secondZone] = t2 + minSameZoneSpacing;
return {
notes: notes,
nextTime: t1 + nextTimeAdvance
};
}
} else if (pattern.type === 'syncHold') {
earliestTime = Math.max(requestedTime, zoneFreeTime.left, zoneFreeTime.right);
var holdDuration = pattern.holdDuration || 1200;
if (earliestTime + holdDuration < sectionEndTime) {
notes.push({
time: earliestTime,
type: 'hold',
zone: 'left',
duration: holdDuration,
color: SYNC_NOTE_COLOR
});
notes.push({
time: earliestTime,
type: 'hold',
zone: 'right',
duration: holdDuration,
color: SYNC_NOTE_COLOR
});
zoneFreeTime.left = earliestTime + holdDuration + 200;
zoneFreeTime.right = earliestTime + holdDuration + 200;
return {
notes: notes,
nextTime: earliestTime + (pattern.duration || 800)
};
}
} else if (pattern.type === 'hold') {
earliestTime = Math.max(requestedTime, zoneFreeTime[pattern.zone]);
var holdDuration = pattern.holdDuration || 1500;
if (earliestTime + holdDuration < sectionEndTime) {
notes.push({
time: earliestTime,
type: 'hold',
zone: pattern.zone,
duration: holdDuration
});
var otherZone = pattern.zone === 'left' ? 'right' : 'left';
zoneFreeTime[pattern.zone] = earliestTime + holdDuration + 200;
zoneFreeTime[otherZone] = Math.max(zoneFreeTime[otherZone], earliestTime + holdDuration + minDiffZoneSpacing);
return {
notes: notes,
nextTime: earliestTime + nextTimeAdvance
};
}
} else if (pattern.type === 'rest') {
return {
notes: [],
nextTime: requestedTime + (pattern.duration || 500)
};
}
return {
notes: [],
nextTime: requestedTime + 100
};
}
};
function _createTutorialText(text, size, yPos, parent, fill, align, customX) {
var textObj = new Text2(text, {
size: size,
fill: fill || 0xFFFFFF,
wordWrap: true,
wordWrapWidth: GAME_WIDTH - 200,
// 100px padding each side
align: align || 'left'
});
if (align === 'center') {
textObj.anchor.set(0.5, 0);
textObj.x = customX || GAME_WIDTH / 2;
} else {
// left align
textObj.anchor.set(0, 0);
textObj.x = customX || 100;
}
textObj.y = yPos;
parent.addChild(textObj);
return textObj;
}
function _createTutorialNoteVisual(assetId, color, xPos, yPos, scale, parent) {
var noteVisual = LK.getAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: scale || 0.35,
scaleY: scale || 0.35
});
noteVisual.tint = color;
noteVisual.x = xPos;
noteVisual.y = yPos;
parent.addChild(noteVisual);
return noteVisual;
}
var SongDatabase = {
'Remember This': {
bpm: 99,
scannerCycleDuration: 4000,
totalLength: 205078,
highScore: storage.highScores && storage.highScores['Remember This'] || 0,
highestGrade: storage.highestGrades && storage.highestGrades['Remember This'] || 'C',
notes: [{
"time": 673,
"type": "tap",
"zone": "right"
}, {
"time": 1277,
"type": "tap",
"zone": "left"
}, {
"time": 2461,
"type": "tap",
"zone": "left"
}, {
"time": 3065,
"type": "tap",
"zone": "right"
}, {
"time": 4249,
"type": "tap",
"zone": "right"
}, {
"time": 4852,
"type": "tap",
"zone": "left"
}, {
"time": 6060,
"type": "tap",
"zone": "left"
}, {
"time": 6664,
"type": "tap",
"zone": "right"
}, {
"time": 7848,
"type": "tap",
"zone": "right"
}, {
"time": 8452,
"type": "tap",
"zone": "left"
}, {
"time": 9659,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 9659,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 10263,
"type": "tap",
"zone": "right"
}, {
"time": 10866,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 12654,
"type": "tap",
"zone": "right"
}, {
"time": 13258,
"type": "tap",
"zone": "left"
}, {
"time": 13862,
"type": "tap",
"zone": "right"
}, {
"time": 14466,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 14466,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 15046,
"type": "tap",
"zone": "right"
}, {
"time": 15650,
"type": "tap",
"zone": "left"
}, {
"time": 16253,
"type": "tap",
"zone": "right"
}, {
"time": 16857,
"type": "tap",
"zone": "left"
}, {
"time": 17257,
"type": "tap",
"zone": "right"
}, {
"time": 18065,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 19853,
"type": "tap",
"zone": "right"
}, {
"time": 20456,
"type": "tap",
"zone": "left"
}, {
"time": 21037,
"type": "tap",
"zone": "right"
}, {
"time": 21640,
"type": "tap",
"zone": "left"
}, {
"time": 22244,
"type": "tap",
"zone": "right"
}, {
"time": 22848,
"type": "tap",
"zone": "left"
}, {
"time": 24055,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 24055,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 24659,
"type": "tap",
"zone": "right"
}, {
"time": 25263,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 27051,
"type": "tap",
"zone": "right"
}, {
"time": 27631,
"type": "tap",
"zone": "left"
}, {
"time": 28258,
"type": "tap",
"zone": "right"
}, {
"time": 28862,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 28862,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 29466,
"type": "tap",
"zone": "right"
}, {
"time": 30046,
"type": "tap",
"zone": "left"
}, {
"time": 31254,
"type": "tap",
"zone": "left"
}, {
"time": 31857,
"type": "tap",
"zone": "right"
}, {
"time": 32461,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 34249,
"type": "tap",
"zone": "right"
}, {
"time": 34853,
"type": "tap",
"zone": "left"
}, {
"time": 35456,
"type": "tap",
"zone": "right"
}, {
"time": 36060,
"type": "tap",
"zone": "left"
}, {
"time": 36641,
"type": "tap",
"zone": "right"
}, {
"time": 37244,
"type": "tap",
"zone": "left"
}, {
"time": 37848,
"type": "tap",
"zone": "right"
}, {
"time": 38475,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 38475,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 39102,
"type": "tap",
"zone": "right"
}, {
"time": 39775,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 41076,
"type": "tap",
"zone": "left"
}, {
"time": 42353,
"type": "tap",
"zone": "left"
}, {
"time": 42956,
"type": "tap",
"zone": "right"
}, {
"time": 44141,
"type": "tap",
"zone": "right"
}, {
"time": 44721,
"type": "tap",
"zone": "left"
}, {
"time": 45325,
"type": "tap",
"zone": "right"
}, {
"time": 45882,
"type": "tap",
"zone": "left"
}, {
"time": 46439,
"type": "tap",
"zone": "right"
}, {
"time": 47531,
"type": "tap",
"zone": "right"
}, {
"time": 48065,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 48065,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 48645,
"type": "tap",
"zone": "right"
}, {
"time": 49249,
"type": "tap",
"zone": "left"
}, {
"time": 49853,
"type": "tap",
"zone": "right"
}, {
"time": 50456,
"type": "tap",
"zone": "left"
}, {
"time": 50856,
"type": "tap",
"zone": "right"
}, {
"time": 51664,
"type": "tap",
"zone": "left"
}, {
"time": 52244,
"type": "tap",
"zone": "right"
}, {
"time": 52848,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 52848,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 53452,
"type": "tap",
"zone": "right"
}, {
"time": 54056,
"type": "tap",
"zone": "left"
}, {
"time": 54659,
"type": "tap",
"zone": "right"
}, {
"time": 55240,
"type": "tap",
"zone": "left"
}, {
"time": 55640,
"type": "tap",
"zone": "right"
}, {
"time": 56447,
"type": "tap",
"zone": "left"
}, {
"time": 57051,
"type": "tap",
"zone": "right"
}, {
"time": 57655,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 57655,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 59443,
"type": "tap",
"zone": "right"
}, {
"time": 60046,
"type": "tap",
"zone": "left"
}, {
"time": 60446,
"type": "tap",
"zone": "right"
}, {
"time": 61254,
"type": "tap",
"zone": "left"
}, {
"time": 61857,
"type": "tap",
"zone": "right"
}, {
"time": 62461,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 62461,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 63065,
"type": "tap",
"zone": "right"
}, {
"time": 63645,
"type": "tap",
"zone": "left"
}, {
"time": 64249,
"type": "tap",
"zone": "right"
}, {
"time": 64853,
"type": "tap",
"zone": "left"
}, {
"time": 65457,
"type": "tap",
"zone": "right"
}, {
"time": 66060,
"type": "tap",
"zone": "left"
}, {
"time": 66664,
"type": "tap",
"zone": "right"
}, {
"time": 67244,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 67244,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 69056,
"type": "tap",
"zone": "right"
}, {
"time": 69659,
"type": "tap",
"zone": "left"
}, {
"time": 70263,
"type": "tap",
"zone": "right"
}, {
"time": 70867,
"type": "tap",
"zone": "left"
}, {
"time": 71447,
"type": "tap",
"zone": "right"
}, {
"time": 72051,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 72051,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 72655,
"type": "tap",
"zone": "right"
}, {
"time": 73258,
"type": "tap",
"zone": "left"
}, {
"time": 73862,
"type": "tap",
"zone": "right"
}, {
"time": 74466,
"type": "tap",
"zone": "left"
}, {
"time": 75046,
"type": "tap",
"zone": "right"
}, {
"time": 75650,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 76858,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 76858,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 78065,
"type": "tap",
"zone": "left"
}, {
"time": 78669,
"type": "tap",
"zone": "right"
}, {
"time": 79876,
"type": "tap",
"zone": "right"
}, {
"time": 80457,
"type": "tap",
"zone": "left"
}, {
"time": 81664,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 81664,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 82245,
"type": "tap",
"zone": "right"
}, {
"time": 82848,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 84056,
"type": "tap",
"zone": "left"
}, {
"time": 84636,
"type": "tap",
"zone": "right"
}, {
"time": 85240,
"type": "tap",
"zone": "left"
}, {
"time": 85844,
"type": "tap",
"zone": "right"
}, {
"time": 86447,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 86447,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 88259,
"type": "tap",
"zone": "right"
}, {
"time": 88862,
"type": "tap",
"zone": "left"
}, {
"time": 89443,
"type": "tap",
"zone": "right"
}, {
"time": 90046,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 91254,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 91254,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 91858,
"type": "tap",
"zone": "right"
}, {
"time": 92461,
"type": "tap",
"zone": "left"
}, {
"time": 93042,
"type": "tap",
"zone": "right"
}, {
"time": 93646,
"type": "tap",
"zone": "left"
}, {
"time": 94249,
"type": "tap",
"zone": "right"
}, {
"time": 94853,
"type": "tap",
"zone": "left"
}, {
"time": 95457,
"type": "tap",
"zone": "right"
}, {
"time": 96060,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 96060,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 96641,
"type": "tap",
"zone": "right"
}, {
"time": 97245,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 98452,
"type": "tap",
"zone": "left"
}, {
"time": 99056,
"type": "tap",
"zone": "right"
}, {
"time": 99660,
"type": "tap",
"zone": "left"
}, {
"time": 100240,
"type": "tap",
"zone": "right"
}, {
"time": 100844,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 100844,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 101447,
"type": "tap",
"zone": "right"
}, {
"time": 102028,
"type": "tap",
"zone": "left"
}, {
"time": 103235,
"type": "tap",
"zone": "left"
}, {
"time": 103862,
"type": "tap",
"zone": "right"
}, {
"time": 105116,
"type": "tap",
"zone": "right"
}, {
"time": 105743,
"type": "tap",
"zone": "left"
}, {
"time": 106881,
"type": "tap",
"zone": "left"
}, {
"time": 107461,
"type": "tap",
"zone": "right"
}, {
"time": 108042,
"type": "tap",
"zone": "left"
}, {
"time": 108646,
"type": "tap",
"zone": "right"
}, {
"time": 109249,
"type": "tap",
"zone": "left"
}, {
"time": 109853,
"type": "tap",
"zone": "right"
}, {
"time": 110457,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 110457,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 111061,
"type": "tap",
"zone": "right"
}, {
"time": 111664,
"type": "tap",
"zone": "left"
}, {
"time": 112245,
"type": "tap",
"zone": "right"
}, {
"time": 112848,
"type": "tap",
"zone": "left"
}, {
"time": 113248,
"type": "tap",
"zone": "right"
}, {
"time": 114056,
"type": "tap",
"zone": "left"
}, {
"time": 114660,
"type": "tap",
"zone": "right"
}, {
"time": 115263,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 115263,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 117051,
"type": "tap",
"zone": "right"
}, {
"time": 117655,
"type": "tap",
"zone": "left"
}, {
"time": 118055,
"type": "tap",
"zone": "right"
}, {
"time": 118862,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 120650,
"type": "tap",
"zone": "right"
}, {
"time": 121254,
"type": "tap",
"zone": "left"
}, {
"time": 121858,
"type": "tap",
"zone": "right"
}, {
"time": 122462,
"type": "tap",
"zone": "left"
}, {
"time": 122862,
"type": "tap",
"zone": "right"
}, {
"time": 123646,
"type": "tap",
"zone": "left"
}, {
"time": 124249,
"type": "tap",
"zone": "right"
}, {
"time": 124853,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 124853,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 125457,
"type": "tap",
"zone": "right"
}, {
"time": 126061,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 128452,
"type": "tap",
"zone": "left"
}, {
"time": 129056,
"type": "tap",
"zone": "right"
}, {
"time": 129660,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 129660,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 130263,
"type": "tap",
"zone": "right"
}, {
"time": 130867,
"type": "tap",
"zone": "left"
}, {
"time": 131448,
"type": "tap",
"zone": "right"
}, {
"time": 132051,
"type": "tap",
"zone": "left"
}, {
"time": 132451,
"type": "tap",
"zone": "right"
}, {
"time": 133259,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 134466,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 134466,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 136254,
"type": "tap",
"zone": "right"
}, {
"time": 136858,
"type": "tap",
"zone": "left"
}, {
"time": 137258,
"type": "tap",
"zone": "right"
}, {
"time": 138042,
"type": "tap",
"zone": "left"
}, {
"time": 138646,
"type": "tap",
"zone": "right"
}, {
"time": 139250,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 139250,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 139853,
"type": "tap",
"zone": "right"
}, {
"time": 140457,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 141664,
"type": "tap",
"zone": "left"
}, {
"time": 142245,
"type": "tap",
"zone": "right"
}, {
"time": 142849,
"type": "tap",
"zone": "left"
}, {
"time": 143452,
"type": "tap",
"zone": "right"
}, {
"time": 144056,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 144056,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 145844,
"type": "tap",
"zone": "right"
}, {
"time": 146448,
"type": "tap",
"zone": "left"
}, {
"time": 147051,
"type": "tap",
"zone": "right"
}, {
"time": 148259,
"type": "tap",
"zone": "right"
}, {
"time": 148839,
"type": "tap",
"zone": "left"
}, {
"time": 150070,
"type": "tap",
"zone": "left"
}, {
"time": 150697,
"type": "tap",
"zone": "right"
}, {
"time": 151904,
"type": "tap",
"zone": "right"
}, {
"time": 152462,
"type": "tap",
"zone": "left"
}, {
"time": 153669,
"type": "tap",
"zone": "left"
}, {
"time": 154273,
"type": "tap",
"zone": "right"
}, {
"time": 155480,
"type": "tap",
"zone": "right"
}, {
"time": 156084,
"type": "tap",
"zone": "left"
}, {
"time": 157268,
"type": "tap",
"zone": "left"
}, {
"time": 157872,
"type": "tap",
"zone": "right"
}, {
"time": 159056,
"type": "tap",
"zone": "right"
}, {
"time": 159613,
"type": "tap",
"zone": "left"
}, {
"time": 160264,
"type": "tap",
"zone": "right"
}, {
"time": 160867,
"type": "tap",
"zone": "left"
}, {
"time": 161448,
"type": "tap",
"zone": "right"
}, {
"time": 162052,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 163259,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 163259,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 163863,
"type": "tap",
"zone": "right"
}, {
"time": 164420,
"type": "tap",
"zone": "left"
}, {
"time": 164977,
"type": "tap",
"zone": "right"
}, {
"time": 165535,
"type": "tap",
"zone": "left"
}, {
"time": 166115,
"type": "tap",
"zone": "right"
}, {
"time": 166719,
"type": "tap",
"zone": "left"
}, {
"time": 167903,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 167903,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 168530,
"type": "tap",
"zone": "right"
}, {
"time": 169250,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 170457,
"type": "tap",
"zone": "left"
}, {
"time": 170857,
"type": "tap",
"zone": "right"
}, {
"time": 171665,
"type": "tap",
"zone": "left"
}, {
"time": 172245,
"type": "tap",
"zone": "right"
}, {
"time": 172849,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 172849,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 174660,
"type": "tap",
"zone": "right"
}, {
"time": 175264,
"type": "tap",
"zone": "left"
}, {
"time": 175664,
"type": "tap",
"zone": "right"
}, {
"time": 176448,
"type": "tap",
"zone": "left"
}, {
"time": 177052,
"type": "tap",
"zone": "right"
}, {
"time": 177655,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 177655,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 178259,
"type": "tap",
"zone": "right"
}, {
"time": 178863,
"type": "tap",
"zone": "left"
}, {
"time": 179443,
"type": "tap",
"zone": "right"
}, {
"time": 180047,
"type": "tap",
"zone": "left"
}, {
"time": 180447,
"type": "tap",
"zone": "right"
}, {
"time": 181254,
"type": "tap",
"zone": "left"
}, {
"time": 181858,
"type": "tap",
"zone": "right"
}, {
"time": 182532,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 182532,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 183205,
"type": "tap",
"zone": "right"
}, {
"time": 184528,
"type": "tap",
"zone": "right"
}, {
"time": 185155,
"type": "tap",
"zone": "left"
}, {
"time": 185555,
"type": "tap",
"zone": "right"
}, {
"time": 186363,
"type": "tap",
"zone": "left"
}, {
"time": 186967,
"type": "tap",
"zone": "right"
}, {
"time": 187547,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 187547,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 188151,
"type": "tap",
"zone": "right"
}, {
"time": 188755,
"type": "tap",
"zone": "left"
}, {
"time": 189358,
"type": "tap",
"zone": "right"
}, {
"time": 189962,
"type": "tap",
"zone": "left"
}, {
"time": 190566,
"type": "tap",
"zone": "right"
}, {
"time": 191146,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 192354,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 192354,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 192957,
"type": "tap",
"zone": "right"
}, {
"time": 193561,
"type": "tap",
"zone": "left"
}, {
"time": 194165,
"type": "tap",
"zone": "right"
}, {
"time": 194745,
"type": "tap",
"zone": "left"
}, {
"time": 195349,
"type": "tap",
"zone": "right"
}, {
"time": 195953,
"type": "tap",
"zone": "left"
}, {
"time": 196556,
"type": "tap",
"zone": "right"
}, {
"time": 197160,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 197160,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 197764,
"type": "tap",
"zone": "right"
}, {
"time": 198344,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 199552,
"type": "tap",
"zone": "left"
}, {
"time": 200156,
"type": "tap",
"zone": "right"
}, {
"time": 200759,
"type": "tap",
"zone": "left"
}]
},
'Arcade Heart': {
bpm: 95,
scannerCycleDuration: 4000,
totalLength: 192446,
highScore: storage.highScores && storage.highScores['Arcade Heart'] || 0,
highestGrade: storage.highestGrades && storage.highestGrades['Arcade Heart'] || 'C',
notes: [{
"time": 1602,
"type": "tap",
"zone": "right"
}, {
"time": 2229,
"type": "tap",
"zone": "left"
}, {
"time": 3482,
"type": "tap",
"zone": "left"
}, {
"time": 4133,
"type": "tap",
"zone": "right"
}, {
"time": 5387,
"type": "tap",
"zone": "right"
}, {
"time": 6013,
"type": "tap",
"zone": "left"
}, {
"time": 7291,
"type": "tap",
"zone": "left"
}, {
"time": 7918,
"type": "tap",
"zone": "right"
}, {
"time": 9171,
"type": "tap",
"zone": "right"
}, {
"time": 9798,
"type": "tap",
"zone": "left"
}, {
"time": 11052,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 11052,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 11702,
"type": "tap",
"zone": "right"
}, {
"time": 12329,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 13583,
"type": "tap",
"zone": "left"
}, {
"time": 14210,
"type": "tap",
"zone": "right"
}, {
"time": 14837,
"type": "tap",
"zone": "left"
}, {
"time": 15487,
"type": "tap",
"zone": "right"
}, {
"time": 16114,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 16114,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 16741,
"type": "tap",
"zone": "right"
}, {
"time": 17368,
"type": "tap",
"zone": "left"
}, {
"time": 18018,
"type": "tap",
"zone": "right"
}, {
"time": 18622,
"type": "tap",
"zone": "left"
}, {
"time": 19272,
"type": "tap",
"zone": "right"
}, {
"time": 19899,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 21153,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 21153,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 21803,
"type": "tap",
"zone": "right"
}, {
"time": 22430,
"type": "tap",
"zone": "left"
}, {
"time": 23057,
"type": "tap",
"zone": "right"
}, {
"time": 23684,
"type": "tap",
"zone": "left"
}, {
"time": 24334,
"type": "tap",
"zone": "right"
}, {
"time": 24938,
"type": "tap",
"zone": "left"
}, {
"time": 25588,
"type": "tap",
"zone": "right"
}, {
"time": 26215,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 26215,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 26865,
"type": "tap",
"zone": "right"
}, {
"time": 27492,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 28746,
"type": "tap",
"zone": "left"
}, {
"time": 29373,
"type": "tap",
"zone": "right"
}, {
"time": 30000,
"type": "tap",
"zone": "left"
}, {
"time": 30650,
"type": "tap",
"zone": "right"
}, {
"time": 31277,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 31277,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 31904,
"type": "tap",
"zone": "right"
}, {
"time": 32531,
"type": "tap",
"zone": "left"
}, {
"time": 33181,
"type": "tap",
"zone": "right"
}, {
"time": 33808,
"type": "tap",
"zone": "left"
}, {
"time": 34435,
"type": "tap",
"zone": "right"
}, {
"time": 35062,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 36316,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 36316,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 36966,
"type": "tap",
"zone": "right"
}, {
"time": 37593,
"type": "tap",
"zone": "left"
}, {
"time": 38220,
"type": "tap",
"zone": "right"
}, {
"time": 38846,
"type": "tap",
"zone": "left"
}, {
"time": 39497,
"type": "tap",
"zone": "right"
}, {
"time": 40124,
"type": "tap",
"zone": "left"
}, {
"time": 40751,
"type": "tap",
"zone": "right"
}, {
"time": 41377,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 41377,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 43281,
"type": "tap",
"zone": "right"
}, {
"time": 43908,
"type": "tap",
"zone": "left"
}, {
"time": 44535,
"type": "tap",
"zone": "right"
}, {
"time": 45162,
"type": "tap",
"zone": "left"
}, {
"time": 45812,
"type": "tap",
"zone": "right"
}, {
"time": 46439,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 46439,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 47066,
"type": "tap",
"zone": "right"
}, {
"time": 47693,
"type": "tap",
"zone": "left"
}, {
"time": 48320,
"type": "tap",
"zone": "right"
}, {
"time": 48947,
"type": "tap",
"zone": "left"
}, {
"time": 49347,
"type": "tap",
"zone": "right"
}, {
"time": 50224,
"type": "tap",
"zone": "left"
}, {
"time": 50851,
"type": "tap",
"zone": "right"
}, {
"time": 51478,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 51478,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 53382,
"type": "tap",
"zone": "right"
}, {
"time": 54009,
"type": "tap",
"zone": "left"
}, {
"time": 54409,
"type": "tap",
"zone": "right"
}, {
"time": 55263,
"type": "tap",
"zone": "left"
}, {
"time": 55913,
"type": "tap",
"zone": "right"
}, {
"time": 56540,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 56540,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 57167,
"type": "tap",
"zone": "right"
}, {
"time": 57794,
"type": "tap",
"zone": "left"
}, {
"time": 58444,
"type": "tap",
"zone": "right"
}, {
"time": 59071,
"type": "tap",
"zone": "left"
}, {
"time": 59698,
"type": "tap",
"zone": "right"
}, {
"time": 60325,
"type": "tap",
"zone": "left"
}, {
"time": 60952,
"type": "tap",
"zone": "right"
}, {
"time": 61602,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 61602,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 62229,
"type": "tap",
"zone": "right"
}, {
"time": 62856,
"type": "tap",
"zone": "left"
}, {
"time": 63483,
"type": "tap",
"zone": "right"
}, {
"time": 64110,
"type": "tap",
"zone": "left"
}, {
"time": 64510,
"type": "tap",
"zone": "right"
}, {
"time": 65387,
"type": "tap",
"zone": "left"
}, {
"time": 66014,
"type": "tap",
"zone": "right"
}, {
"time": 66641,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 66641,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 67268,
"type": "tap",
"zone": "right"
}, {
"time": 67918,
"type": "tap",
"zone": "left"
}, {
"time": 68545,
"type": "tap",
"zone": "right"
}, {
"time": 69799,
"type": "tap",
"zone": "right"
}, {
"time": 70426,
"type": "tap",
"zone": "left"
}, {
"time": 71703,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 71703,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 72330,
"type": "tap",
"zone": "right"
}, {
"time": 72957,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 74210,
"type": "tap",
"zone": "left"
}, {
"time": 74837,
"type": "tap",
"zone": "right"
}, {
"time": 75488,
"type": "tap",
"zone": "left"
}, {
"time": 76115,
"type": "tap",
"zone": "right"
}, {
"time": 76741,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 76741,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 77392,
"type": "tap",
"zone": "right"
}, {
"time": 78019,
"type": "tap",
"zone": "left"
}, {
"time": 78645,
"type": "tap",
"zone": "right"
}, {
"time": 79272,
"type": "tap",
"zone": "left"
}, {
"time": 79899,
"type": "tap",
"zone": "right"
}, {
"time": 80526,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 81803,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 81803,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 82430,
"type": "tap",
"zone": "right"
}, {
"time": 83057,
"type": "tap",
"zone": "left"
}, {
"time": 83684,
"type": "tap",
"zone": "right"
}, {
"time": 84311,
"type": "tap",
"zone": "left"
}, {
"time": 84961,
"type": "tap",
"zone": "right"
}, {
"time": 85588,
"type": "tap",
"zone": "left"
}, {
"time": 86215,
"type": "tap",
"zone": "right"
}, {
"time": 86842,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 86842,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 87492,
"type": "tap",
"zone": "right"
}, {
"time": 88119,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 89373,
"type": "tap",
"zone": "left"
}, {
"time": 90000,
"type": "tap",
"zone": "right"
}, {
"time": 90650,
"type": "tap",
"zone": "left"
}, {
"time": 91277,
"type": "tap",
"zone": "right"
}, {
"time": 91904,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 91904,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 92531,
"type": "tap",
"zone": "right"
}, {
"time": 93158,
"type": "tap",
"zone": "left"
}, {
"time": 93808,
"type": "tap",
"zone": "right"
}, {
"time": 94435,
"type": "tap",
"zone": "left"
}, {
"time": 95062,
"type": "tap",
"zone": "right"
}, {
"time": 95689,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 96966,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 96966,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 97593,
"type": "tap",
"zone": "right"
}, {
"time": 98220,
"type": "tap",
"zone": "left"
}, {
"time": 98870,
"type": "tap",
"zone": "right"
}, {
"time": 100101,
"type": "tap",
"zone": "right"
}, {
"time": 100751,
"type": "tap",
"zone": "left"
}, {
"time": 101378,
"type": "tap",
"zone": "right"
}, {
"time": 102005,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 102005,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 102632,
"type": "tap",
"zone": "right"
}, {
"time": 103282,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 104536,
"type": "tap",
"zone": "left"
}, {
"time": 104936,
"type": "tap",
"zone": "right"
}, {
"time": 105790,
"type": "tap",
"zone": "left"
}, {
"time": 106440,
"type": "tap",
"zone": "right"
}, {
"time": 107067,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 107067,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 107694,
"type": "tap",
"zone": "right"
}, {
"time": 108321,
"type": "tap",
"zone": "left"
}, {
"time": 108948,
"type": "tap",
"zone": "right"
}, {
"time": 109574,
"type": "tap",
"zone": "left"
}, {
"time": 109974,
"type": "tap",
"zone": "right"
}, {
"time": 110852,
"type": "tap",
"zone": "left"
}, {
"time": 111479,
"type": "tap",
"zone": "right"
}, {
"time": 112129,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 112129,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 112756,
"type": "tap",
"zone": "right"
}, {
"time": 113383,
"type": "tap",
"zone": "left"
}, {
"time": 114009,
"type": "tap",
"zone": "right"
}, {
"time": 114636,
"type": "tap",
"zone": "left"
}, {
"time": 115036,
"type": "tap",
"zone": "right"
}, {
"time": 115890,
"type": "tap",
"zone": "left"
}, {
"time": 116540,
"type": "tap",
"zone": "right"
}, {
"time": 117167,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 117167,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 117794,
"type": "tap",
"zone": "right"
}, {
"time": 118421,
"type": "tap",
"zone": "left"
}, {
"time": 119071,
"type": "tap",
"zone": "right"
}, {
"time": 119698,
"type": "tap",
"zone": "left"
}, {
"time": 120302,
"type": "tap",
"zone": "right"
}, {
"time": 120952,
"type": "tap",
"zone": "left"
}, {
"time": 121602,
"type": "tap",
"zone": "right"
}, {
"time": 122229,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 122229,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 122856,
"type": "tap",
"zone": "right"
}, {
"time": 123483,
"type": "tap",
"zone": "left"
}, {
"time": 124110,
"type": "tap",
"zone": "right"
}, {
"time": 124737,
"type": "tap",
"zone": "left"
}, {
"time": 125137,
"type": "tap",
"zone": "right"
}, {
"time": 126014,
"type": "tap",
"zone": "left"
}, {
"time": 126641,
"type": "tap",
"zone": "right"
}, {
"time": 127268,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 127268,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 127895,
"type": "tap",
"zone": "right"
}, {
"time": 128522,
"type": "tap",
"zone": "left"
}, {
"time": 129172,
"type": "tap",
"zone": "right"
}, {
"time": 129799,
"type": "tap",
"zone": "left"
}, {
"time": 130199,
"type": "tap",
"zone": "right"
}, {
"time": 131053,
"type": "tap",
"zone": "left"
}, {
"time": 131703,
"type": "tap",
"zone": "right"
}, {
"time": 132330,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 132330,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 132957,
"type": "tap",
"zone": "right"
}, {
"time": 133584,
"type": "tap",
"zone": "left"
}, {
"time": 134211,
"type": "tap",
"zone": "right"
}, {
"time": 134838,
"type": "tap",
"zone": "left"
}, {
"time": 135238,
"type": "tap",
"zone": "right"
}, {
"time": 136115,
"type": "tap",
"zone": "left"
}, {
"time": 136672,
"type": "tap",
"zone": "right"
}, {
"time": 137856,
"type": "tap",
"zone": "right"
}, {
"time": 138483,
"type": "tap",
"zone": "left"
}, {
"time": 139760,
"type": "tap",
"zone": "left"
}, {
"time": 140387,
"type": "tap",
"zone": "right"
}, {
"time": 141664,
"type": "tap",
"zone": "right"
}, {
"time": 142291,
"type": "tap",
"zone": "left"
}, {
"time": 143592,
"type": "tap",
"zone": "left"
}, {
"time": 144288,
"type": "tap",
"zone": "right"
}, {
"time": 145705,
"type": "tap",
"zone": "right"
}, {
"time": 146308,
"type": "tap",
"zone": "left"
}, {
"time": 147516,
"type": "tap",
"zone": "left"
}, {
"time": 148143,
"type": "tap",
"zone": "right"
}, {
"time": 149397,
"type": "tap",
"zone": "right"
}, {
"time": 150024,
"type": "tap",
"zone": "left"
}, {
"time": 151278,
"type": "tap",
"zone": "left"
}, {
"time": 151904,
"type": "tap",
"zone": "right"
}, {
"time": 152531,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 152531,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 153205,
"type": "tap",
"zone": "right"
}, {
"time": 153948,
"type": "tap",
"zone": "left"
}, {
"time": 154598,
"type": "tap",
"zone": "right"
}, {
"time": 155225,
"type": "tap",
"zone": "left"
}, {
"time": 155852,
"type": "tap",
"zone": "right"
}, {
"time": 156502,
"type": "tap",
"zone": "left"
}, {
"time": 157129,
"type": "tap",
"zone": "right"
}, {
"time": 157756,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 157756,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 158383,
"type": "tap",
"zone": "right"
}, {
"time": 159010,
"type": "tap",
"zone": "left"
}, {
"time": 159567,
"type": "tap",
"zone": "right"
}, {
"time": 160682,
"type": "tap",
"zone": "right"
}, {
"time": 161378,
"type": "tap",
"zone": "left"
}, {
"time": 162005,
"type": "tap",
"zone": "right"
}, {
"time": 162655,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 162655,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 164536,
"type": "tap",
"zone": "right"
}, {
"time": 165163,
"type": "tap",
"zone": "left"
}, {
"time": 165563,
"type": "tap",
"zone": "right"
}, {
"time": 166440,
"type": "tap",
"zone": "left"
}, {
"time": 167067,
"type": "tap",
"zone": "right"
}, {
"time": 167694,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 167694,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 168321,
"type": "tap",
"zone": "right"
}, {
"time": 168948,
"type": "tap",
"zone": "left"
}, {
"time": 169598,
"type": "tap",
"zone": "right"
}, {
"time": 170225,
"type": "tap",
"zone": "left"
}, {
"time": 170625,
"type": "tap",
"zone": "right"
}, {
"time": 171479,
"type": "tap",
"zone": "left"
}, {
"time": 172106,
"type": "tap",
"zone": "right"
}, {
"time": 172756,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 172756,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 174637,
"type": "tap",
"zone": "right"
}, {
"time": 175264,
"type": "tap",
"zone": "left"
}, {
"time": 175664,
"type": "tap",
"zone": "right"
}, {
"time": 176541,
"type": "tap",
"zone": "left"
}, {
"time": 177168,
"type": "tap",
"zone": "right"
}, {
"time": 177795,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 177795,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 178422,
"type": "tap",
"zone": "right"
}, {
"time": 179049,
"type": "tap",
"zone": "left"
}, {
"time": 179629,
"type": "tap",
"zone": "right"
}, {
"time": 180210,
"type": "tap",
"zone": "left"
}, {
"time": 180813,
"type": "tap",
"zone": "right"
}, {
"time": 181440,
"type": "tap",
"zone": "left"
}, {
"time": 182067,
"type": "tap",
"zone": "right"
}, {
"time": 183344,
"type": "tap",
"zone": "right"
}, {
"time": 183994,
"type": "tap",
"zone": "left"
}, {
"time": 185225,
"type": "tap",
"zone": "left"
}, {
"time": 185852,
"type": "tap",
"zone": "right"
}, {
"time": 187129,
"type": "tap",
"zone": "right"
}, {
"time": 187733,
"type": "tap",
"zone": "left"
}]
},
'Pixel Paradise': {
bpm: 117,
scannerCycleDuration: 4000,
totalLength: 202106,
highScore: storage.highScores && storage.highScores['Pixel Paradise'] || 0,
highestGrade: storage.highestGrades && storage.highestGrades['Pixel Paradise'] || 'C',
notes: [{
"time": 2000,
"type": "tap",
"zone": "left"
}, {
"time": 3000,
"type": "tap",
"zone": "left"
}, {
"time": 4000,
"type": "tap",
"zone": "left"
}, {
"time": 4500,
"type": "tap",
"zone": "right"
}, {
"time": 5000,
"type": "tap",
"zone": "left"
}, {
"time": 5500,
"type": "tap",
"zone": "right"
}, {
"time": 6000,
"type": "tap",
"zone": "left",
"color": 0xFFA500
}, {
"time": 6000,
"type": "tap",
"zone": "right",
"color": 0xFFA500
}, {
"time": 7000,
"type": "tap",
"zone": "right"
}, {
"time": 8707,
"type": "tap",
"zone": "right"
}, {
"time": 9218,
"type": "tap",
"zone": "left"
}, {
"time": 9705,
"type": "tap",
"zone": "right"
}, {
"time": 10216,
"type": "tap",
"zone": "left"
}, {
"time": 10704,
"type": "tap",
"zone": "right"
}, {
"time": 11215,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 12701,
"type": "tap",
"zone": "right"
}, {
"time": 13212,
"type": "tap",
"zone": "left"
}, {
"time": 13699,
"type": "tap",
"zone": "right"
}, {
"time": 14210,
"type": "tap",
"zone": "left"
}, {
"time": 14610,
"type": "tap",
"zone": "right"
}, {
"time": 15209,
"type": "tap",
"zone": "left"
}, {
"time": 15696,
"type": "tap",
"zone": "right"
}, {
"time": 16207,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 16207,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 18204,
"type": "tap",
"zone": "left"
}, {
"time": 18692,
"type": "tap",
"zone": "right"
}, {
"time": 19202,
"type": "tap",
"zone": "left"
}, {
"time": 19690,
"type": "tap",
"zone": "right"
}, {
"time": 20201,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 20201,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 20712,
"type": "tap",
"zone": "right"
}, {
"time": 21199,
"type": "tap",
"zone": "left"
}, {
"time": 22198,
"type": "tap",
"zone": "left"
}, {
"time": 22709,
"type": "tap",
"zone": "right"
}, {
"time": 23196,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 24682,
"type": "tap",
"zone": "right"
}, {
"time": 25193,
"type": "tap",
"zone": "left"
}, {
"time": 25704,
"type": "tap",
"zone": "right"
}, {
"time": 26215,
"type": "tap",
"zone": "left"
}, {
"time": 26702,
"type": "tap",
"zone": "right"
}, {
"time": 27213,
"type": "tap",
"zone": "left"
}, {
"time": 27701,
"type": "tap",
"zone": "right"
}, {
"time": 28212,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 28212,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 28699,
"type": "tap",
"zone": "right"
}, {
"time": 29210,
"type": "tap",
"zone": "left"
}, {
"time": 29698,
"type": "tap",
"zone": "right"
}, {
"time": 30209,
"type": "tap",
"zone": "left"
}, {
"time": 30609,
"type": "tap",
"zone": "right"
}, {
"time": 31161,
"type": "tap",
"zone": "left"
}, {
"time": 31672,
"type": "tap",
"zone": "right"
}, {
"time": 32182,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 32182,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 34202,
"type": "tap",
"zone": "left"
}, {
"time": 34602,
"type": "tap",
"zone": "right"
}, {
"time": 35201,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 36710,
"type": "tap",
"zone": "right"
}, {
"time": 37198,
"type": "tap",
"zone": "left"
}, {
"time": 37709,
"type": "tap",
"zone": "right"
}, {
"time": 38196,
"type": "tap",
"zone": "left"
}, {
"time": 38707,
"type": "tap",
"zone": "right"
}, {
"time": 39195,
"type": "tap",
"zone": "left"
}, {
"time": 39682,
"type": "tap",
"zone": "right"
}, {
"time": 40216,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 40216,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 40704,
"type": "tap",
"zone": "right"
}, {
"time": 41215,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 43212,
"type": "tap",
"zone": "left"
}, {
"time": 43699,
"type": "tap",
"zone": "right"
}, {
"time": 44721,
"type": "tap",
"zone": "right"
}, {
"time": 45209,
"type": "tap",
"zone": "left"
}, {
"time": 45696,
"type": "tap",
"zone": "right"
}, {
"time": 46207,
"type": "tap",
"zone": "left"
}, {
"time": 46718,
"type": "tap",
"zone": "right"
}, {
"time": 47693,
"type": "tap",
"zone": "right"
}, {
"time": 48204,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 48204,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 48715,
"type": "tap",
"zone": "right"
}, {
"time": 49203,
"type": "tap",
"zone": "left"
}, {
"time": 49713,
"type": "tap",
"zone": "right"
}, {
"time": 50201,
"type": "tap",
"zone": "left"
}, {
"time": 50712,
"type": "tap",
"zone": "right"
}, {
"time": 51200,
"type": "tap",
"zone": "left"
}, {
"time": 51710,
"type": "tap",
"zone": "right"
}, {
"time": 52221,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 52221,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 52709,
"type": "tap",
"zone": "right"
}, {
"time": 53220,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 54706,
"type": "tap",
"zone": "right"
}, {
"time": 55217,
"type": "tap",
"zone": "left"
}, {
"time": 55704,
"type": "tap",
"zone": "right"
}, {
"time": 56192,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 56192,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 56703,
"type": "tap",
"zone": "right"
}, {
"time": 57190,
"type": "tap",
"zone": "left"
}, {
"time": 57701,
"type": "tap",
"zone": "right"
}, {
"time": 58212,
"type": "tap",
"zone": "left"
}, {
"time": 58700,
"type": "tap",
"zone": "right"
}, {
"time": 59210,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 60696,
"type": "tap",
"zone": "right"
}, {
"time": 61207,
"type": "tap",
"zone": "left"
}, {
"time": 61695,
"type": "tap",
"zone": "right"
}, {
"time": 62183,
"type": "tap",
"zone": "left"
}, {
"time": 62693,
"type": "tap",
"zone": "right"
}, {
"time": 63204,
"type": "tap",
"zone": "left"
}, {
"time": 63715,
"type": "tap",
"zone": "right"
}, {
"time": 64203,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 64203,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 64714,
"type": "tap",
"zone": "right"
}, {
"time": 65201,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 66710,
"type": "tap",
"zone": "right"
}, {
"time": 67198,
"type": "tap",
"zone": "left"
}, {
"time": 67709,
"type": "tap",
"zone": "right"
}, {
"time": 68220,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 68220,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 68707,
"type": "tap",
"zone": "right"
}, {
"time": 69195,
"type": "tap",
"zone": "left"
}, {
"time": 69706,
"type": "tap",
"zone": "right"
}, {
"time": 70217,
"type": "tap",
"zone": "left"
}, {
"time": 70617,
"type": "tap",
"zone": "right"
}, {
"time": 71215,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 72701,
"type": "tap",
"zone": "right"
}, {
"time": 73189,
"type": "tap",
"zone": "left"
}, {
"time": 73700,
"type": "tap",
"zone": "right"
}, {
"time": 74210,
"type": "tap",
"zone": "left"
}, {
"time": 74698,
"type": "tap",
"zone": "right"
}, {
"time": 75209,
"type": "tap",
"zone": "left"
}, {
"time": 75697,
"type": "tap",
"zone": "right"
}, {
"time": 76207,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 76207,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 76695,
"type": "tap",
"zone": "right"
}, {
"time": 77206,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 78692,
"type": "tap",
"zone": "right"
}, {
"time": 79203,
"type": "tap",
"zone": "left"
}, {
"time": 79690,
"type": "tap",
"zone": "right"
}, {
"time": 80201,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 80201,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 80689,
"type": "tap",
"zone": "right"
}, {
"time": 81200,
"type": "tap",
"zone": "left"
}, {
"time": 81711,
"type": "tap",
"zone": "right"
}, {
"time": 82221,
"type": "tap",
"zone": "left"
}, {
"time": 82709,
"type": "tap",
"zone": "right"
}, {
"time": 83197,
"type": "tap",
"zone": "left"
}, {
"time": 83707,
"type": "tap",
"zone": "right"
}, {
"time": 84218,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 84218,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 84706,
"type": "tap",
"zone": "right"
}, {
"time": 85217,
"type": "tap",
"zone": "left"
}, {
"time": 85704,
"type": "tap",
"zone": "right"
}, {
"time": 86215,
"type": "tap",
"zone": "left"
}, {
"time": 86615,
"type": "tap",
"zone": "right"
}, {
"time": 87167,
"type": "tap",
"zone": "left"
}, {
"time": 87678,
"type": "tap",
"zone": "right"
}, {
"time": 88166,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 88166,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 90209,
"type": "tap",
"zone": "left"
}, {
"time": 90609,
"type": "tap",
"zone": "right"
}, {
"time": 91184,
"type": "tap",
"zone": "left"
}, {
"time": 91695,
"type": "tap",
"zone": "right"
}, {
"time": 92206,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 92206,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 92694,
"type": "tap",
"zone": "right"
}, {
"time": 93204,
"type": "tap",
"zone": "left"
}, {
"time": 93692,
"type": "tap",
"zone": "right"
}, {
"time": 94203,
"type": "tap",
"zone": "left"
}, {
"time": 94714,
"type": "tap",
"zone": "right"
}, {
"time": 95201,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 96711,
"type": "tap",
"zone": "right"
}, {
"time": 97221,
"type": "tap",
"zone": "left"
}, {
"time": 97709,
"type": "tap",
"zone": "right"
}, {
"time": 98197,
"type": "tap",
"zone": "left"
}, {
"time": 98708,
"type": "tap",
"zone": "right"
}, {
"time": 99195,
"type": "tap",
"zone": "left"
}, {
"time": 100217,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 100217,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 100704,
"type": "tap",
"zone": "right"
}, {
"time": 101703,
"type": "tap",
"zone": "right"
}, {
"time": 102214,
"type": "tap",
"zone": "left"
}, {
"time": 103212,
"type": "tap",
"zone": "left"
}, {
"time": 103700,
"type": "tap",
"zone": "right"
}, {
"time": 104211,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 104211,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 106208,
"type": "tap",
"zone": "left"
}, {
"time": 106608,
"type": "tap",
"zone": "right"
}, {
"time": 107206,
"type": "tap",
"zone": "left"
}, {
"time": 107694,
"type": "tap",
"zone": "right"
}, {
"time": 108204,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 108204,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 108692,
"type": "tap",
"zone": "right"
}, {
"time": 109203,
"type": "tap",
"zone": "left"
}, {
"time": 109691,
"type": "tap",
"zone": "right"
}, {
"time": 110201,
"type": "tap",
"zone": "left"
}, {
"time": 110601,
"type": "tap",
"zone": "right"
}, {
"time": 111200,
"type": "tap",
"zone": "left"
}, {
"time": 111711,
"type": "tap",
"zone": "right"
}, {
"time": 112198,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 112198,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 114195,
"type": "tap",
"zone": "left"
}, {
"time": 114595,
"type": "tap",
"zone": "right"
}, {
"time": 115194,
"type": "tap",
"zone": "left"
}, {
"time": 115705,
"type": "tap",
"zone": "right"
}, {
"time": 116215,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 116215,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 116703,
"type": "tap",
"zone": "right"
}, {
"time": 117191,
"type": "tap",
"zone": "left"
}, {
"time": 117701,
"type": "tap",
"zone": "right"
}, {
"time": 118189,
"type": "tap",
"zone": "left"
}, {
"time": 118700,
"type": "tap",
"zone": "right"
}, {
"time": 119698,
"type": "tap",
"zone": "right"
}, {
"time": 120209,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 120209,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 122206,
"type": "tap",
"zone": "left"
}, {
"time": 122606,
"type": "tap",
"zone": "right"
}, {
"time": 123205,
"type": "tap",
"zone": "left"
}, {
"time": 123715,
"type": "tap",
"zone": "right"
}, {
"time": 124203,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 124203,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 124714,
"type": "tap",
"zone": "right"
}, {
"time": 125201,
"type": "tap",
"zone": "left"
}, {
"time": 125712,
"type": "tap",
"zone": "right"
}, {
"time": 126200,
"type": "tap",
"zone": "left"
}, {
"time": 126600,
"type": "tap",
"zone": "right"
}, {
"time": 127198,
"type": "tap",
"zone": "left"
}, {
"time": 127709,
"type": "tap",
"zone": "right"
}, {
"time": 128684,
"type": "tap",
"zone": "right"
}, {
"time": 129195,
"type": "tap",
"zone": "left"
}, {
"time": 130217,
"type": "tap",
"zone": "left"
}, {
"time": 130705,
"type": "tap",
"zone": "right"
}, {
"time": 131750,
"type": "tap",
"zone": "right"
}, {
"time": 132260,
"type": "tap",
"zone": "left"
}, {
"time": 133189,
"type": "tap",
"zone": "left"
}, {
"time": 133677,
"type": "tap",
"zone": "right"
}, {
"time": 134675,
"type": "tap",
"zone": "right"
}, {
"time": 135186,
"type": "tap",
"zone": "left"
}, {
"time": 136208,
"type": "tap",
"zone": "left"
}, {
"time": 136719,
"type": "tap",
"zone": "right"
}, {
"time": 137717,
"type": "tap",
"zone": "right"
}, {
"time": 138228,
"type": "tap",
"zone": "left"
}, {
"time": 139226,
"type": "tap",
"zone": "left"
}, {
"time": 139714,
"type": "tap",
"zone": "right"
}, {
"time": 140202,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 140202,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 140712,
"type": "tap",
"zone": "right"
}, {
"time": 141223,
"type": "tap",
"zone": "left"
}, {
"time": 142222,
"type": "tap",
"zone": "left"
}, {
"time": 142709,
"type": "tap",
"zone": "right"
}, {
"time": 143708,
"type": "tap",
"zone": "right"
}, {
"time": 144195,
"type": "tap",
"zone": "left"
}, {
"time": 145194,
"type": "tap",
"zone": "left"
}, {
"time": 145705,
"type": "tap",
"zone": "right"
}, {
"time": 146216,
"type": "tap",
"zone": "left"
}, {
"time": 146703,
"type": "tap",
"zone": "right"
}, {
"time": 147214,
"type": "tap",
"zone": "left"
}, {
"time": 147702,
"type": "tap",
"zone": "right"
}, {
"time": 148212,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 148212,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 148700,
"type": "tap",
"zone": "right"
}, {
"time": 149699,
"type": "tap",
"zone": "right"
}, {
"time": 150209,
"type": "tap",
"zone": "left"
}, {
"time": 151208,
"type": "tap",
"zone": "left"
}, {
"time": 151695,
"type": "tap",
"zone": "right"
}, {
"time": 152206,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 152206,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 154203,
"type": "tap",
"zone": "left"
}, {
"time": 154714,
"type": "tap",
"zone": "right"
}, {
"time": 155202,
"type": "tap",
"zone": "left"
}, {
"time": 155713,
"type": "tap",
"zone": "right"
}, {
"time": 156200,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 156200,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 157222,
"type": "tap",
"zone": "left"
}, {
"time": 157709,
"type": "tap",
"zone": "right"
}, {
"time": 158220,
"type": "tap",
"zone": "left"
}, {
"time": 158708,
"type": "tap",
"zone": "right"
}, {
"time": 159219,
"type": "tap",
"zone": "left"
}, {
"time": 159706,
"type": "tap",
"zone": "right"
}, {
"time": 160217,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 160217,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 160728,
"type": "tap",
"zone": "right"
}, {
"time": 161726,
"type": "tap",
"zone": "right"
}, {
"time": 162214,
"type": "tap",
"zone": "left"
}, {
"time": 163213,
"type": "tap",
"zone": "left"
}, {
"time": 163700,
"type": "tap",
"zone": "right"
}, {
"time": 164211,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 164211,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 164699,
"type": "tap",
"zone": "right"
}, {
"time": 165209,
"type": "tap",
"zone": "left"
}, {
"time": 165697,
"type": "tap",
"zone": "right"
}, {
"time": 166208,
"type": "tap",
"zone": "left"
}, {
"time": 166608,
"type": "tap",
"zone": "right"
}, {
"time": 167206,
"type": "tap",
"zone": "left"
}, {
"time": 167717,
"type": "tap",
"zone": "right"
}, {
"time": 168205,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 168205,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 170202,
"type": "tap",
"zone": "left"
}, {
"time": 170602,
"type": "tap",
"zone": "right"
}, {
"time": 171200,
"type": "tap",
"zone": "left"
}, {
"time": 171711,
"type": "tap",
"zone": "right"
}, {
"time": 172199,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 172199,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 172710,
"type": "tap",
"zone": "right"
}, {
"time": 173197,
"type": "tap",
"zone": "left"
}, {
"time": 173708,
"type": "tap",
"zone": "right"
}, {
"time": 174196,
"type": "tap",
"zone": "left"
}, {
"time": 175217,
"type": "tap",
"zone": "left"
}, {
"time": 175705,
"type": "tap",
"zone": "right"
}, {
"time": 176216,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 176216,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 176703,
"type": "tap",
"zone": "right"
}, {
"time": 177214,
"type": "tap",
"zone": "left"
}, {
"time": 177702,
"type": "tap",
"zone": "right"
}, {
"time": 178213,
"type": "tap",
"zone": "left"
}, {
"time": 178700,
"type": "tap",
"zone": "right"
}, {
"time": 179211,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 180697,
"type": "tap",
"zone": "right"
}, {
"time": 181208,
"type": "tap",
"zone": "left"
}, {
"time": 181719,
"type": "tap",
"zone": "right"
}, {
"time": 182206,
"type": "tap",
"zone": "left"
}, {
"time": 182606,
"type": "tap",
"zone": "right"
}, {
"time": 183205,
"type": "tap",
"zone": "left"
}, {
"time": 183716,
"type": "tap",
"zone": "right"
}, {
"time": 184203,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 184203,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 184714,
"type": "tap",
"zone": "right"
}, {
"time": 185202,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 186711,
"type": "tap",
"zone": "right"
}, {
"time": 187222,
"type": "tap",
"zone": "left"
}, {
"time": 187710,
"type": "tap",
"zone": "right"
}, {
"time": 188197,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 188197,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 188708,
"type": "tap",
"zone": "right"
}, {
"time": 189219,
"type": "tap",
"zone": "left"
}, {
"time": 189823,
"type": "tap",
"zone": "right"
}, {
"time": 190403,
"type": "tap",
"zone": "left"
}, {
"time": 190803,
"type": "tap",
"zone": "right"
}, {
"time": 191448,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 193468,
"type": "tap",
"zone": "left"
}, {
"time": 193956,
"type": "tap",
"zone": "right"
}, {
"time": 194954,
"type": "tap",
"zone": "right"
}, {
"time": 195465,
"type": "tap",
"zone": "left"
}, {
"time": 196464,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 196464,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 196974,
"type": "tap",
"zone": "right"
}, {
"time": 197973,
"type": "tap",
"zone": "right"
}, {
"time": 198460,
"type": "tap",
"zone": "left"
}, {
"time": 198971,
"type": "tap",
"zone": "right"
}]
},
'Runner': {
bpm: 92,
scannerCycleDuration: 4000,
totalLength: 230341,
highScore: storage.highScores && storage.highScores['Runner'] || 0,
highestGrade: storage.highestGrades && storage.highestGrades['Runner'] || 'C',
notes: [{
"time": 208,
"type": "tap",
"zone": "left"
}, {
"time": 1671,
"type": "tap",
"zone": "left"
}, {
"time": 2972,
"type": "tap",
"zone": "left"
}, {
"time": 4272,
"type": "tap",
"zone": "left"
}, {
"time": 5247,
"type": "tap",
"zone": "right"
}, {
"time": 5572,
"type": "tap",
"zone": "left"
}, {
"time": 6873,
"type": "tap",
"zone": "left"
}, {
"time": 8173,
"type": "tap",
"zone": "left"
}, {
"time": 9496,
"type": "tap",
"zone": "left"
}, {
"time": 10472,
"type": "tap",
"zone": "right"
}, {
"time": 10797,
"type": "tap",
"zone": "left"
}, {
"time": 11772,
"type": "tap",
"zone": "right"
}, {
"time": 12097,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 13397,
"type": "tap",
"zone": "left"
}, {
"time": 13722,
"type": "tap",
"zone": "right"
}, {
"time": 14048,
"type": "tap",
"zone": "left"
}, {
"time": 14721,
"type": "tap",
"zone": "left"
}, {
"time": 15046,
"type": "tap",
"zone": "right"
}, {
"time": 16021,
"type": "tap",
"zone": "left"
}, {
"time": 17322,
"type": "tap",
"zone": "left"
}, {
"time": 17647,
"type": "tap",
"zone": "right"
}, {
"time": 18622,
"type": "tap",
"zone": "left"
}, {
"time": 18947,
"type": "tap",
"zone": "right"
}, {
"time": 19272,
"type": "tap",
"zone": "left"
}, {
"time": 19945,
"type": "tap",
"zone": "left"
}, {
"time": 21223,
"type": "tap",
"zone": "left"
}, {
"time": 21548,
"type": "tap",
"zone": "right"
}, {
"time": 22523,
"type": "tap",
"zone": "left"
}, {
"time": 23846,
"type": "tap",
"zone": "left"
}, {
"time": 25147,
"type": "tap",
"zone": "left"
}, {
"time": 26447,
"type": "tap",
"zone": "left"
}, {
"time": 26772,
"type": "tap",
"zone": "right"
}, {
"time": 27747,
"type": "tap",
"zone": "left"
}, {
"time": 29048,
"type": "tap",
"zone": "left"
}, {
"time": 30348,
"type": "tap",
"zone": "left"
}, {
"time": 31672,
"type": "tap",
"zone": "left"
}, {
"time": 31997,
"type": "tap",
"zone": "right"
}, {
"time": 32322,
"type": "tap",
"zone": "left"
}, {
"time": 32647,
"type": "tap",
"zone": "right"
}, {
"time": 32972,
"type": "tap",
"zone": "left"
}, {
"time": 33947,
"type": "tap",
"zone": "right"
}, {
"time": 34272,
"type": "tap",
"zone": "left"
}, {
"time": 34597,
"type": "tap",
"zone": "right"
}, {
"time": 34922,
"type": "tap",
"zone": "left"
}, {
"time": 35247,
"type": "tap",
"zone": "right"
}, {
"time": 35572,
"type": "tap",
"zone": "left"
}, {
"time": 36873,
"type": "tap",
"zone": "left"
}, {
"time": 38173,
"type": "tap",
"zone": "left"
}, {
"time": 39497,
"type": "tap",
"zone": "left"
}, {
"time": 40797,
"type": "tap",
"zone": "left"
}, {
"time": 42097,
"type": "tap",
"zone": "left"
}, {
"time": 42422,
"type": "tap",
"zone": "right"
}, {
"time": 42747,
"type": "tap",
"zone": "left"
}, {
"time": 43073,
"type": "tap",
"zone": "right"
}, {
"time": 43398,
"type": "tap",
"zone": "left"
}, {
"time": 43723,
"type": "tap",
"zone": "right"
}, {
"time": 44048,
"type": "tap",
"zone": "left"
}, {
"time": 44373,
"type": "tap",
"zone": "right"
}, {
"time": 44698,
"type": "tap",
"zone": "left"
}, {
"time": 45023,
"type": "tap",
"zone": "right"
}, {
"time": 45348,
"type": "tap",
"zone": "left"
}, {
"time": 45673,
"type": "tap",
"zone": "right"
}, {
"time": 45998,
"type": "tap",
"zone": "left"
}, {
"time": 46323,
"type": "tap",
"zone": "right"
}, {
"time": 46648,
"type": "tap",
"zone": "left"
}, {
"time": 46985,
"type": "tap",
"zone": "right"
}, {
"time": 47322,
"type": "tap",
"zone": "left"
}, {
"time": 47647,
"type": "tap",
"zone": "right"
}, {
"time": 47972,
"type": "tap",
"zone": "left"
}, {
"time": 48622,
"type": "tap",
"zone": "left"
}, {
"time": 48947,
"type": "tap",
"zone": "right"
}, {
"time": 49272,
"type": "tap",
"zone": "left"
}, {
"time": 49597,
"type": "tap",
"zone": "right"
}, {
"time": 49922,
"type": "tap",
"zone": "left"
}, {
"time": 50247,
"type": "tap",
"zone": "right"
}, {
"time": 50573,
"type": "tap",
"zone": "left"
}, {
"time": 51223,
"type": "tap",
"zone": "left"
}, {
"time": 51896,
"type": "tap",
"zone": "left"
}, {
"time": 52221,
"type": "tap",
"zone": "right"
}, {
"time": 52546,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 52546,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 52871,
"type": "tap",
"zone": "right"
}, {
"time": 53196,
"type": "tap",
"zone": "left"
}, {
"time": 53521,
"type": "tap",
"zone": "right"
}, {
"time": 53847,
"type": "tap",
"zone": "left"
}, {
"time": 54172,
"type": "tap",
"zone": "right"
}, {
"time": 54822,
"type": "tap",
"zone": "right"
}, {
"time": 55147,
"type": "tap",
"zone": "left"
}, {
"time": 55472,
"type": "tap",
"zone": "right"
}, {
"time": 56122,
"type": "tap",
"zone": "right"
}, {
"time": 56447,
"type": "tap",
"zone": "left"
}, {
"time": 56772,
"type": "tap",
"zone": "right"
}, {
"time": 57422,
"type": "tap",
"zone": "right"
}, {
"time": 57748,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 57748,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 58073,
"type": "tap",
"zone": "right"
}, {
"time": 58398,
"type": "tap",
"zone": "left"
}, {
"time": 58723,
"type": "tap",
"zone": "right"
}, {
"time": 59048,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 60371,
"type": "tap",
"zone": "left"
}, {
"time": 60696,
"type": "tap",
"zone": "right"
}, {
"time": 61022,
"type": "tap",
"zone": "left"
}, {
"time": 61347,
"type": "tap",
"zone": "right"
}, {
"time": 61672,
"type": "tap",
"zone": "left"
}, {
"time": 61997,
"type": "tap",
"zone": "right"
}, {
"time": 62322,
"type": "tap",
"zone": "left"
}, {
"time": 62647,
"type": "tap",
"zone": "right"
}, {
"time": 62972,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 62972,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 63297,
"type": "tap",
"zone": "right"
}, {
"time": 63622,
"type": "tap",
"zone": "left"
}, {
"time": 63947,
"type": "tap",
"zone": "right"
}, {
"time": 64272,
"type": "tap",
"zone": "left"
}, {
"time": 64597,
"type": "tap",
"zone": "right"
}, {
"time": 64922,
"type": "tap",
"zone": "left"
}, {
"time": 65248,
"type": "tap",
"zone": "right"
}, {
"time": 65573,
"type": "tap",
"zone": "left"
}, {
"time": 65898,
"type": "tap",
"zone": "right"
}, {
"time": 66223,
"type": "tap",
"zone": "left"
}, {
"time": 66548,
"type": "tap",
"zone": "right"
}, {
"time": 66873,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 67871,
"type": "tap",
"zone": "right"
}, {
"time": 68197,
"type": "tap",
"zone": "left"
}, {
"time": 68522,
"type": "tap",
"zone": "right"
}, {
"time": 69172,
"type": "tap",
"zone": "right"
}, {
"time": 69497,
"type": "tap",
"zone": "left"
}, {
"time": 69822,
"type": "tap",
"zone": "right"
}, {
"time": 70147,
"type": "tap",
"zone": "left"
}, {
"time": 70472,
"type": "tap",
"zone": "right"
}, {
"time": 70797,
"type": "tap",
"zone": "left"
}, {
"time": 71122,
"type": "tap",
"zone": "right"
}, {
"time": 71447,
"type": "tap",
"zone": "left"
}, {
"time": 71772,
"type": "tap",
"zone": "right"
}, {
"time": 72097,
"type": "tap",
"zone": "left"
}, {
"time": 73398,
"type": "tap",
"zone": "left"
}, {
"time": 73723,
"type": "tap",
"zone": "right"
}, {
"time": 74048,
"type": "tap",
"zone": "left"
}, {
"time": 74373,
"type": "tap",
"zone": "right"
}, {
"time": 74698,
"type": "tap",
"zone": "left"
}, {
"time": 76022,
"type": "tap",
"zone": "left"
}, {
"time": 76347,
"type": "tap",
"zone": "right"
}, {
"time": 76997,
"type": "tap",
"zone": "right"
}, {
"time": 77322,
"type": "tap",
"zone": "left"
}, {
"time": 78297,
"type": "tap",
"zone": "right"
}, {
"time": 78622,
"type": "tap",
"zone": "left"
}, {
"time": 78947,
"type": "tap",
"zone": "right"
}, {
"time": 79272,
"type": "tap",
"zone": "left"
}, {
"time": 79923,
"type": "tap",
"zone": "left"
}, {
"time": 81223,
"type": "tap",
"zone": "left"
}, {
"time": 81548,
"type": "tap",
"zone": "right"
}, {
"time": 81873,
"type": "tap",
"zone": "left"
}, {
"time": 82198,
"type": "tap",
"zone": "right"
}, {
"time": 82523,
"type": "tap",
"zone": "left"
}, {
"time": 83173,
"type": "tap",
"zone": "left"
}, {
"time": 83510,
"type": "tap",
"zone": "right"
}, {
"time": 83847,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 83847,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 84172,
"type": "tap",
"zone": "right"
}, {
"time": 84497,
"type": "tap",
"zone": "left"
}, {
"time": 84822,
"type": "tap",
"zone": "right"
}, {
"time": 85147,
"type": "tap",
"zone": "left"
}, {
"time": 85472,
"type": "tap",
"zone": "right"
}, {
"time": 85797,
"type": "tap",
"zone": "left"
}, {
"time": 86122,
"type": "tap",
"zone": "right"
}, {
"time": 86447,
"type": "tap",
"zone": "left"
}, {
"time": 86772,
"type": "tap",
"zone": "right"
}, {
"time": 87098,
"type": "tap",
"zone": "left"
}, {
"time": 87423,
"type": "tap",
"zone": "right"
}, {
"time": 87748,
"type": "tap",
"zone": "left"
}, {
"time": 88073,
"type": "tap",
"zone": "right"
}, {
"time": 88398,
"type": "tap",
"zone": "left"
}, {
"time": 88723,
"type": "tap",
"zone": "right"
}, {
"time": 89048,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 89048,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 89373,
"type": "tap",
"zone": "right"
}, {
"time": 90348,
"type": "tap",
"zone": "left"
}, {
"time": 91335,
"type": "tap",
"zone": "right"
}, {
"time": 91672,
"type": "tap",
"zone": "left"
}, {
"time": 91997,
"type": "tap",
"zone": "right"
}, {
"time": 92322,
"type": "tap",
"zone": "left"
}, {
"time": 92647,
"type": "tap",
"zone": "right"
}, {
"time": 92972,
"type": "tap",
"zone": "left"
}, {
"time": 93297,
"type": "tap",
"zone": "right"
}, {
"time": 93622,
"type": "tap",
"zone": "left"
}, {
"time": 93947,
"type": "tap",
"zone": "right"
}, {
"time": 94273,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 94273,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 94598,
"type": "tap",
"zone": "right"
}, {
"time": 94923,
"type": "tap",
"zone": "left"
}, {
"time": 95248,
"type": "tap",
"zone": "right"
}, {
"time": 95573,
"type": "tap",
"zone": "left"
}, {
"time": 95898,
"type": "tap",
"zone": "right"
}, {
"time": 96223,
"type": "tap",
"zone": "left"
}, {
"time": 96548,
"type": "tap",
"zone": "right"
}, {
"time": 96873,
"type": "tap",
"zone": "left"
}, {
"time": 97198,
"type": "tap",
"zone": "right"
}, {
"time": 97523,
"type": "tap",
"zone": "left"
}, {
"time": 97848,
"type": "tap",
"zone": "right"
}, {
"time": 98173,
"type": "tap",
"zone": "left"
}, {
"time": 98499,
"type": "tap",
"zone": "right"
}, {
"time": 98824,
"type": "tap",
"zone": "left"
}, {
"time": 99160,
"type": "tap",
"zone": "right"
}, {
"time": 99497,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 99497,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 99822,
"type": "tap",
"zone": "right"
}, {
"time": 100147,
"type": "tap",
"zone": "left"
}, {
"time": 100472,
"type": "tap",
"zone": "right"
}, {
"time": 100797,
"type": "tap",
"zone": "left"
}, {
"time": 101122,
"type": "tap",
"zone": "right"
}, {
"time": 101447,
"type": "tap",
"zone": "left"
}, {
"time": 101773,
"type": "tap",
"zone": "right"
}, {
"time": 102098,
"type": "tap",
"zone": "left"
}, {
"time": 103421,
"type": "tap",
"zone": "left"
}, {
"time": 104396,
"type": "tap",
"zone": "right"
}, {
"time": 104721,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 104721,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 106672,
"type": "tap",
"zone": "left"
}, {
"time": 106997,
"type": "tap",
"zone": "right"
}, {
"time": 107322,
"type": "tap",
"zone": "left"
}, {
"time": 107647,
"type": "tap",
"zone": "right"
}, {
"time": 107972,
"type": "tap",
"zone": "left"
}, {
"time": 108297,
"type": "tap",
"zone": "right"
}, {
"time": 108622,
"type": "tap",
"zone": "left"
}, {
"time": 108948,
"type": "tap",
"zone": "right"
}, {
"time": 109273,
"type": "tap",
"zone": "left"
}, {
"time": 109598,
"type": "tap",
"zone": "right"
}, {
"time": 109923,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 109923,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 110248,
"type": "tap",
"zone": "right"
}, {
"time": 110573,
"type": "tap",
"zone": "left"
}, {
"time": 110898,
"type": "tap",
"zone": "right"
}, {
"time": 111223,
"type": "tap",
"zone": "left"
}, {
"time": 111548,
"type": "tap",
"zone": "right"
}, {
"time": 111873,
"type": "tap",
"zone": "left"
}, {
"time": 112210,
"type": "tap",
"zone": "right"
}, {
"time": 112547,
"type": "tap",
"zone": "left"
}, {
"time": 112872,
"type": "tap",
"zone": "right"
}, {
"time": 113197,
"type": "tap",
"zone": "left"
}, {
"time": 113522,
"type": "tap",
"zone": "right"
}, {
"time": 113847,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 114822,
"type": "tap",
"zone": "right"
}, {
"time": 115147,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 115147,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 117098,
"type": "tap",
"zone": "left"
}, {
"time": 117423,
"type": "tap",
"zone": "right"
}, {
"time": 117748,
"type": "tap",
"zone": "left"
}, {
"time": 118073,
"type": "tap",
"zone": "right"
}, {
"time": 118398,
"type": "tap",
"zone": "left"
}, {
"time": 118723,
"type": "tap",
"zone": "right"
}, {
"time": 119048,
"type": "tap",
"zone": "left"
}, {
"time": 119385,
"type": "tap",
"zone": "right"
}, {
"time": 119722,
"type": "tap",
"zone": "left"
}, {
"time": 120047,
"type": "tap",
"zone": "right"
}, {
"time": 120372,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 120372,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 120697,
"type": "tap",
"zone": "right"
}, {
"time": 121022,
"type": "tap",
"zone": "left"
}, {
"time": 121347,
"type": "tap",
"zone": "right"
}, {
"time": 121672,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 122322,
"type": "tap",
"zone": "left"
}, {
"time": 122972,
"type": "tap",
"zone": "left"
}, {
"time": 123297,
"type": "tap",
"zone": "right"
}, {
"time": 123623,
"type": "tap",
"zone": "left"
}, {
"time": 123948,
"type": "tap",
"zone": "right"
}, {
"time": 124273,
"type": "tap",
"zone": "left"
}, {
"time": 125573,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 125573,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 125898,
"type": "tap",
"zone": "right"
}, {
"time": 126548,
"type": "tap",
"zone": "right"
}, {
"time": 126873,
"type": "tap",
"zone": "left"
}, {
"time": 127198,
"type": "tap",
"zone": "right"
}, {
"time": 127523,
"type": "tap",
"zone": "left"
}, {
"time": 127849,
"type": "tap",
"zone": "right"
}, {
"time": 128174,
"type": "tap",
"zone": "left"
}, {
"time": 128510,
"type": "tap",
"zone": "right"
}, {
"time": 129172,
"type": "tap",
"zone": "right"
}, {
"time": 129497,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 130472,
"type": "tap",
"zone": "right"
}, {
"time": 130798,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 130798,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 131123,
"type": "tap",
"zone": "right"
}, {
"time": 131448,
"type": "tap",
"zone": "left"
}, {
"time": 131773,
"type": "tap",
"zone": "right"
}, {
"time": 132098,
"type": "tap",
"zone": "left"
}, {
"time": 132423,
"type": "tap",
"zone": "right"
}, {
"time": 132748,
"type": "tap",
"zone": "left"
}, {
"time": 133073,
"type": "tap",
"zone": "right"
}, {
"time": 133398,
"type": "tap",
"zone": "left"
}, {
"time": 133723,
"type": "tap",
"zone": "right"
}, {
"time": 134373,
"type": "tap",
"zone": "right"
}, {
"time": 134698,
"type": "tap",
"zone": "left"
}, {
"time": 135035,
"type": "tap",
"zone": "right"
}, {
"time": 135372,
"type": "tap",
"zone": "left"
}, {
"time": 135697,
"type": "tap",
"zone": "right"
}, {
"time": 136022,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 136022,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 136347,
"type": "tap",
"zone": "right"
}, {
"time": 136672,
"type": "tap",
"zone": "left"
}, {
"time": 136997,
"type": "tap",
"zone": "right"
}, {
"time": 137322,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 138623,
"type": "tap",
"zone": "left"
}, {
"time": 138948,
"type": "tap",
"zone": "right"
}, {
"time": 139598,
"type": "tap",
"zone": "right"
}, {
"time": 139923,
"type": "tap",
"zone": "left"
}, {
"time": 140248,
"type": "tap",
"zone": "right"
}, {
"time": 140573,
"type": "tap",
"zone": "left"
}, {
"time": 140898,
"type": "tap",
"zone": "right"
}, {
"time": 141223,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 141223,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 141548,
"type": "tap",
"zone": "right"
}, {
"time": 141873,
"type": "tap",
"zone": "left"
}, {
"time": 142199,
"type": "tap",
"zone": "right"
}, {
"time": 142524,
"type": "tap",
"zone": "left"
}, {
"time": 142849,
"type": "tap",
"zone": "right"
}, {
"time": 143174,
"type": "tap",
"zone": "left"
}, {
"time": 143510,
"type": "tap",
"zone": "right"
}, {
"time": 143847,
"type": "tap",
"zone": "left"
}, {
"time": 144172,
"type": "tap",
"zone": "right"
}, {
"time": 144497,
"type": "tap",
"zone": "left"
}, {
"time": 144822,
"type": "tap",
"zone": "right"
}, {
"time": 145147,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 146123,
"type": "tap",
"zone": "right"
}, {
"time": 146448,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 146448,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 146773,
"type": "tap",
"zone": "right"
}, {
"time": 147098,
"type": "tap",
"zone": "left"
}, {
"time": 147423,
"type": "tap",
"zone": "right"
}, {
"time": 147748,
"type": "tap",
"zone": "left"
}, {
"time": 148073,
"type": "tap",
"zone": "right"
}, {
"time": 148398,
"type": "tap",
"zone": "left"
}, {
"time": 148723,
"type": "tap",
"zone": "right"
}, {
"time": 149048,
"type": "tap",
"zone": "left"
}, {
"time": 149373,
"type": "tap",
"zone": "right"
}, {
"time": 149699,
"type": "tap",
"zone": "left"
}, {
"time": 150024,
"type": "tap",
"zone": "right"
}, {
"time": 150349,
"type": "tap",
"zone": "left"
}, {
"time": 150685,
"type": "tap",
"zone": "right"
}, {
"time": 151022,
"type": "tap",
"zone": "left"
}, {
"time": 151347,
"type": "tap",
"zone": "right"
}, {
"time": 151672,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 151672,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 151997,
"type": "tap",
"zone": "right"
}, {
"time": 152322,
"type": "tap",
"zone": "left"
}, {
"time": 152647,
"type": "tap",
"zone": "right"
}, {
"time": 152973,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 154273,
"type": "tap",
"zone": "left"
}, {
"time": 154598,
"type": "tap",
"zone": "right"
}, {
"time": 154923,
"type": "tap",
"zone": "left"
}, {
"time": 155573,
"type": "tap",
"zone": "left"
}, {
"time": 156874,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 156874,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 158174,
"type": "tap",
"zone": "left"
}, {
"time": 159161,
"type": "tap",
"zone": "right"
}, {
"time": 159497,
"type": "tap",
"zone": "left"
}, {
"time": 159822,
"type": "tap",
"zone": "right"
}, {
"time": 160148,
"type": "tap",
"zone": "left"
}, {
"time": 160473,
"type": "tap",
"zone": "right"
}, {
"time": 160798,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 161773,
"type": "tap",
"zone": "right"
}, {
"time": 162098,
"type": "tap",
"zone": "left"
}, {
"time": 163398,
"type": "tap",
"zone": "left"
}, {
"time": 164374,
"type": "tap",
"zone": "right"
}, {
"time": 164699,
"type": "tap",
"zone": "left"
}, {
"time": 165024,
"type": "tap",
"zone": "right"
}, {
"time": 165349,
"type": "tap",
"zone": "left"
}, {
"time": 165674,
"type": "tap",
"zone": "right"
}, {
"time": 165999,
"type": "tap",
"zone": "left"
}, {
"time": 166324,
"type": "tap",
"zone": "right"
}, {
"time": 166649,
"type": "tap",
"zone": "left"
}, {
"time": 166986,
"type": "tap",
"zone": "right"
}, {
"time": 167322,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 167322,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 167973,
"type": "tap",
"zone": "left"
}, {
"time": 168623,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 169923,
"type": "tap",
"zone": "left"
}, {
"time": 170573,
"type": "tap",
"zone": "left"
}, {
"time": 171223,
"type": "tap",
"zone": "left"
}, {
"time": 171874,
"type": "tap",
"zone": "left"
}, {
"time": 172199,
"type": "tap",
"zone": "right"
}, {
"time": 172524,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 172524,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 172849,
"type": "tap",
"zone": "right"
}, {
"time": 173174,
"type": "tap",
"zone": "left"
}, {
"time": 173499,
"type": "tap",
"zone": "right"
}, {
"time": 173824,
"type": "tap",
"zone": "left"
}, {
"time": 174161,
"type": "tap",
"zone": "right"
}, {
"time": 174497,
"type": "tap",
"zone": "left"
}, {
"time": 175148,
"type": "tap",
"zone": "left"
}, {
"time": 175473,
"type": "tap",
"zone": "right"
}, {
"time": 175798,
"type": "tap",
"zone": "left"
}, {
"time": 176587,
"type": "tap",
"zone": "left"
}, {
"time": 177528,
"type": "tap",
"zone": "right"
}, {
"time": 177818,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 177818,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 179699,
"type": "tap",
"zone": "left"
}, {
"time": 180024,
"type": "tap",
"zone": "right"
}, {
"time": 180349,
"type": "tap",
"zone": "left"
}, {
"time": 180674,
"type": "tap",
"zone": "right"
}, {
"time": 180999,
"type": "tap",
"zone": "left"
}, {
"time": 181324,
"type": "tap",
"zone": "right"
}, {
"time": 181649,
"type": "tap",
"zone": "left"
}, {
"time": 181974,
"type": "tap",
"zone": "right"
}, {
"time": 182299,
"type": "tap",
"zone": "left"
}, {
"time": 182624,
"type": "tap",
"zone": "right"
}, {
"time": 182950,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 182950,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 183275,
"type": "tap",
"zone": "right"
}, {
"time": 183600,
"type": "tap",
"zone": "left"
}, {
"time": 183925,
"type": "tap",
"zone": "right"
}, {
"time": 184250,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 185550,
"type": "tap",
"zone": "left"
}, {
"time": 185887,
"type": "tap",
"zone": "right"
}, {
"time": 186224,
"type": "tap",
"zone": "left"
}, {
"time": 186549,
"type": "tap",
"zone": "right"
}, {
"time": 186874,
"type": "tap",
"zone": "left"
}, {
"time": 187524,
"type": "tap",
"zone": "left"
}, {
"time": 187849,
"type": "tap",
"zone": "right"
}, {
"time": 188174,
"type": "hold",
"zone": "left",
"duration": 1500,
"color": 16753920
}, {
"time": 188174,
"type": "hold",
"zone": "right",
"duration": 1500,
"color": 16753920
}, {
"time": 190124,
"type": "tap",
"zone": "left"
}, {
"time": 190450,
"type": "tap",
"zone": "right"
}, {
"time": 190775,
"type": "tap",
"zone": "left"
}, {
"time": 191100,
"type": "tap",
"zone": "right"
}, {
"time": 191425,
"type": "tap",
"zone": "left"
}, {
"time": 191750,
"type": "tap",
"zone": "right"
}, {
"time": 192075,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 192400,
"type": "tap",
"zone": "right"
}, {
"time": 193399,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 193399,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 194699,
"type": "tap",
"zone": "left"
}, {
"time": 195674,
"type": "tap",
"zone": "right"
}, {
"time": 195999,
"type": "tap",
"zone": "left"
}, {
"time": 196324,
"type": "tap",
"zone": "right"
}, {
"time": 196649,
"type": "tap",
"zone": "left"
}, {
"time": 196974,
"type": "tap",
"zone": "right"
}, {
"time": 197299,
"type": "tap",
"zone": "left"
}, {
"time": 198600,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 198600,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 199900,
"type": "tap",
"zone": "left"
}, {
"time": 201200,
"type": "tap",
"zone": "left"
}, {
"time": 201851,
"type": "tap",
"zone": "left"
}, {
"time": 202524,
"type": "tap",
"zone": "left"
}, {
"time": 203174,
"type": "tap",
"zone": "left"
}, {
"time": 203499,
"type": "tap",
"zone": "right"
}, {
"time": 203824,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 203824,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 205125,
"type": "tap",
"zone": "left"
}, {
"time": 205775,
"type": "tap",
"zone": "left"
}, {
"time": 206425,
"type": "tap",
"zone": "left"
}, {
"time": 207075,
"type": "tap",
"zone": "left"
}, {
"time": 207725,
"type": "hold",
"zone": "left",
"duration": 1000
}, {
"time": 208724,
"type": "tap",
"zone": "right"
}, {
"time": 209049,
"type": "tap",
"zone": "left",
"color": 16753920
}, {
"time": 209049,
"type": "tap",
"zone": "right",
"color": 16753920
}, {
"time": 209699,
"type": "tap",
"zone": "left"
}, {
"time": 210349,
"type": "tap",
"zone": "left"
}, {
"time": 211649,
"type": "tap",
"zone": "left"
}, {
"time": 212950,
"type": "tap",
"zone": "left"
}, {
"time": 213600,
"type": "tap",
"zone": "left"
}, {
"time": 214250,
"type": "tap",
"zone": "left"
}, {
"time": 214900,
"type": "tap",
"zone": "left"
}, {
"time": 215550,
"type": "hold",
"zone": "right",
"duration": 1000
}, {
"time": 216874,
"type": "tap",
"zone": "left"
}, {
"time": 217524,
"type": "tap",
"zone": "left"
}, {
"time": 217849,
"type": "tap",
"zone": "right"
}, {
"time": 218174,
"type": "tap",
"zone": "left"
}, {
"time": 218499,
"type": "tap",
"zone": "right"
}, {
"time": 218824,
"type": "tap",
"zone": "left"
}, {
"time": 219428,
"type": "tap",
"zone": "left"
}, {
"time": 220636,
"type": "tap",
"zone": "left"
}, {
"time": 221936,
"type": "tap",
"zone": "left"
}, {
"time": 223236,
"type": "tap",
"zone": "left"
}, {
"time": 224536,
"type": "tap",
"zone": "left"
}, {
"time": 225837,
"type": "tap",
"zone": "left"
}, {
"time": 227137,
"type": "tap",
"zone": "left"
}]
}
};
function getSongLength(songName) {
var song = SongDatabase[songName];
if (!song) {
return "0:00";
}
var totalSeconds = Math.floor(song.totalLength / 1000);
var minutes = Math.floor(totalSeconds / 60);
var seconds = totalSeconds % 60;
return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
}
function updateHighScore(songName, score, grade) {
var updated = false;
if (SongDatabase[songName]) {
if (score > SongDatabase[songName].highScore) {
SongDatabase[songName].highScore = score;
// Save high scores to storage
if (!storage.highScores) {
storage.highScores = {};
}
storage.highScores[songName] = score;
updated = true;
}
// Update grade if it's better (S > A > B > C)
var currentGrade = SongDatabase[songName].highestGrade || 'C';
var gradeOrder = ['C', 'B', 'A', 'S'];
if (gradeOrder.indexOf(grade) > gradeOrder.indexOf(currentGrade)) {
SongDatabase[songName].highestGrade = grade;
// Save highest grades to storage
if (!storage.highestGrades) {
storage.highestGrades = {};
}
storage.highestGrades[songName] = grade;
updated = true;
}
}
return updated;
}
function calculateNotePosition(noteTime) {
var cycleTime = noteTime % SCANNER_CYCLE_DURATION;
var y;
if (cycleTime < SCANNER_HALF_CYCLE) {
var progress = cycleTime / SCANNER_HALF_CYCLE;
y = SCANNER_Y_MAX - progress * PLAY_AREA_HEIGHT;
} else {
var progress = (cycleTime - SCANNER_HALF_CYCLE) / SCANNER_HALF_CYCLE;
y = SCANNER_Y_MIN + progress * PLAY_AREA_HEIGHT;
}
return y;
}
function calculateZoneX(zone, noteY, endNoteY) {
var sideMargin = GAME_WIDTH * SAFETY_MARGIN_SIDES_PERCENT;
var randomSpan = GAME_WIDTH / 2 - 2 * sideMargin;
if (randomSpan < 0) {
randomSpan = 0;
}
// Check if note or its end note is in the bottom 15% of the play area
var isInBottomArea = noteY > SCANNER_Y_MAX - PLAY_AREA_HEIGHT * 0.20;
if (endNoteY !== undefined) {
isInBottomArea = isInBottomArea || endNoteY > SCANNER_Y_MAX - PLAY_AREA_HEIGHT * 0.15;
}
var xPosition;
if (zone === 'left') {
xPosition = sideMargin;
if (isInBottomArea) {
// In bottom area, favor the right side of the left zone (more central)
// Use the right 60% of the left zone's available space
var centralSpan = randomSpan * 0.5;
var offset = randomSpan * 0.5; // Skip the leftmost 40%
xPosition += offset + Math.random() * centralSpan;
} else {
// Normal positioning for upper areas
xPosition += Math.random() * randomSpan;
}
} else {
xPosition = GAME_WIDTH / 2 + sideMargin;
if (isInBottomArea) {
// In bottom area, favor the left side of the right zone (more central)
// Use the left 60% of the right zone's available space
var centralSpan = randomSpan * 0.5;
xPosition += Math.random() * centralSpan;
} else {
// Normal positioning for upper areas
xPosition += Math.random() * randomSpan;
}
}
return xPosition;
}
function createZoneIndicators() {
leftZone = game.attachAsset('zoneIndicator', {
anchorX: 0,
anchorY: 0
});
leftZone.x = 0;
leftZone.y = 0;
leftZone.width = GAME_WIDTH / 2;
leftZone.alpha = 0.1;
leftZone.tint = 0x00ffff;
rightZone = game.attachAsset('zoneIndicator', {
anchorX: 0,
anchorY: 0
});
rightZone.x = GAME_WIDTH / 2;
rightZone.y = 0;
rightZone.width = GAME_WIDTH / 2;
rightZone.alpha = 0.1;
rightZone.tint = 0xff00ff;
}
function showAccuracyPopup(text, x, y, color) {
var popup = new Text2(text, {
size: ACCURACY_POPUP_FONT_SIZE,
fill: color,
stroke: 0x000000,
strokeThickness: 4
});
popup.anchor.set(0.5, 0.5);
popup.x = x;
popup.y = y + ACCURACY_POPUP_Y_OFFSET;
popup.alpha = 0;
game.addChild(popup);
var initialY = popup.y;
tween(popup, {
alpha: 1,
y: initialY - 30
}, {
duration: ACCURACY_POPUP_DURATION * 0.25,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(popup, {
alpha: 0,
y: initialY - 130
}, {
duration: ACCURACY_POPUP_DURATION * 0.75,
easing: tween.easeIn,
onFinish: function onFinish() {
if (popup && popup.destroy) {
popup.destroy();
}
}
});
}
});
}
function initializeTitleScreen() {
titleScreen.container = new Container();
game.addChild(titleScreen.container);
titleScreen.title = titleScreen.container.attachAsset('titleImage', {
anchorX: 0.5,
anchorY: 0.5
});
titleScreen.title.x = GAME_WIDTH / 2;
titleScreen.title.y = GAME_HEIGHT / 2 - 200;
titleScreen.subtitle = new Text2('Press to Start', {
size: 100,
fill: 0xCCCCCC
});
titleScreen.subtitle.anchor.set(0.5, 0.5);
titleScreen.subtitle.x = GAME_WIDTH / 2;
titleScreen.subtitle.y = GAME_HEIGHT / 2 + 100 + GAME_HEIGHT * 0.15;
titleScreen.container.addChild(titleScreen.subtitle);
var pulseScale = 1;
var pulseDirection = 1;
titleScreen.pulseInterval = LK.setInterval(function () {
pulseScale += pulseDirection * 0.02;
if (pulseScale > 1.1) {
pulseScale = 1.1;
pulseDirection = -1;
} else if (pulseScale < 0.9) {
pulseScale = 0.9;
pulseDirection = 1;
}
titleScreen.subtitle.scale.set(pulseScale);
}, 50);
}
function initializeSongSelectScreen() {
songSelectScreen.container = new Container();
game.addChild(songSelectScreen.container);
songSelectScreen.container.visible = false;
songSelectScreen.title = new Text2('Select Song', {
size: 150,
fill: 0xFFFFFF
});
songSelectScreen.title.anchor.set(0.5, 0);
songSelectScreen.title.x = GAME_WIDTH / 2;
songSelectScreen.title.y = 100;
songSelectScreen.container.addChild(songSelectScreen.title);
songSelectScreen.scrollContainer = new Container();
songSelectScreen.scrollContainer.x = 0;
songSelectScreen.scrollContainer.y = 300;
songSelectScreen.container.addChild(songSelectScreen.scrollContainer);
createSongItems();
updateScrollLimits();
songSelectScreen.tutorialButton = new Text2('How to Play', {
size: 90,
fill: 0xCCCCCC
});
songSelectScreen.tutorialButton.anchor.set(0.5, 1);
songSelectScreen.tutorialButton.x = GAME_WIDTH / 2;
songSelectScreen.tutorialButton.y = GAME_HEIGHT - 60; // Positioned at the bottom
songSelectScreen.container.addChild(songSelectScreen.tutorialButton);
}
function createSongItems() {
songSelectScreen.items = [];
var songNames = Object.keys(SongDatabase);
for (var i = 0; i < songNames.length; i++) {
var songName = songNames[i];
var song = SongDatabase[songName];
var yPos = i * (SONG_ITEM_HEIGHT + 50);
var itemContainer = new Container();
itemContainer.x = 100;
itemContainer.y = yPos;
itemContainer.songName = songName;
var bg = game.attachAsset('zoneIndicator', {
anchorX: 0,
anchorY: 0
});
bg.width = GAME_WIDTH - 200;
bg.height = SONG_ITEM_HEIGHT;
bg.alpha = 0.2;
bg.tint = 0x333333;
itemContainer.addChild(bg);
var displayName = songName;
if (songName === 'Runner') {
displayName = songName + ' (Hard)';
}
var titleText = new Text2(displayName, {
size: 100,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0); // Center horizontally, align top vertically
titleText.x = (GAME_WIDTH - 200) / 2; // Center within the background width
titleText.y = 30;
itemContainer.addChild(titleText);
// Define vertical padding between text elements
var verticalPadding = 20;
var infoText = new Text2('BPM: ' + song.bpm + ' | Length: ' + getSongLength(songName), {
size: 62.5,
fill: 0xCCCCCC
});
infoText.anchor.set(0.5, 0); // Center horizontally, align top vertically
infoText.x = (GAME_WIDTH - 200) / 2; // Center within the background width
// Position infoText below titleText (assuming titleText font size 100 is approx height)
infoText.y = titleText.y + 100 + verticalPadding;
itemContainer.addChild(infoText);
var gradeDisplay = song.highestGrade || 'C';
var scoreText = new Text2('High Score: ' + song.highScore + ' | Grade: ' + gradeDisplay, {
size: 62.5,
fill: 0xFFDD00
});
scoreText.anchor.set(0.5, 0); // Center horizontally, align top vertically
scoreText.x = (GAME_WIDTH - 200) / 2; // Center within the background width
// Position scoreText below infoText (assuming infoText font size 62.5 is approx height)
scoreText.y = infoText.y + 62.5 + verticalPadding;
itemContainer.addChild(scoreText);
songSelectScreen.scrollContainer.addChild(itemContainer);
songSelectScreen.items.push(itemContainer);
}
}
function updateScrollLimits() {
var totalHeight = songSelectScreen.items.length * (SONG_ITEM_HEIGHT + 50);
var containerHeight = GAME_HEIGHT - 400;
maxScrollY = Math.max(0, totalHeight - containerHeight);
}
function showTitleScreen() {
currentGameState = GAME_STATE_TITLE;
if (titleScreen.container) {
titleScreen.container.visible = true;
}
if (songSelectScreen.container) {
songSelectScreen.container.visible = false;
}
if (resultsScreen.container) {
resultsScreen.container.visible = false;
}
if (tutorialScreen.container) {
tutorialScreen.container.visible = false;
}
hideGameplayUI();
}
function showSongSelectScreen() {
currentGameState = GAME_STATE_SONG_SELECT;
if (titleScreen.container) {
titleScreen.container.visible = false;
}
if (songSelectScreen.container) {
songSelectScreen.container.visible = true;
}
if (resultsScreen.container) {
resultsScreen.container.visible = false;
}
if (tutorialScreen.container) {
tutorialScreen.container.visible = false;
}
songSelectionInProgress = false; // Reset flag when song select screen is shown
hideGameplayUI();
songSelectScrollY = 0;
songSelectScreen.scrollContainer.y = 300;
}
function hideGameplayUI() {
if (scoreTxt) {
scoreTxt.visible = false;
}
// Zone indicators removed - no longer hiding background zones
// if (leftZone) {
// leftZone.visible = false;
// }
// if (rightZone) {
// rightZone.visible = false;
// }
if (scanner) {
scanner.visible = false;
}
// Also ensure tutorial is hidden if gameplay UI is hidden for other reasons
if (tutorialScreen.container && currentGameState !== GAME_STATE_TUTORIAL) {
tutorialScreen.container.visible = false;
}
}
function showGameplayUI() {
if (scoreTxt) {
scoreTxt.visible = true;
}
// Zone indicators removed - no longer showing background zones
// if (leftZone) {
// leftZone.visible = true;
// }
// if (rightZone) {
// rightZone.visible = true;
// }
if (scanner) {
scanner.visible = true;
}
if (titleScreen.container) {
titleScreen.container.visible = false;
}
if (songSelectScreen.container) {
songSelectScreen.container.visible = false;
}
if (tutorialScreen.container) {
tutorialScreen.container.visible = false;
}
if (resultsScreen.container) {
resultsScreen.container.visible = false;
}
}
function startCountdown() {
countdownTxt = new Text2('3', {
size: 200,
fill: 0xFFFFFF
});
countdownTxt.anchor.set(0.5, 0.5);
countdownTxt.x = GAME_WIDTH / 2;
countdownTxt.y = GAME_HEIGHT / 2;
game.addChild(countdownTxt);
// Start countdown acceleration
isCountdownActive = true;
countdownAcceleration = 1;
var startTime = Date.now();
var countdownDuration = 4000; // 4 seconds total
var count = 3;
var countdownInterval = LK.setInterval(function () {
count--;
if (count > 0) {
countdownTxt.setText(count.toString());
} else if (count === 0) {
countdownTxt.setText('GO!');
} else {
LK.clearInterval(countdownInterval);
if (countdownTxt && countdownTxt.destroy) {
countdownTxt.destroy();
}
// Keep the accelerated speed when game starts
baseParticleSpeed = 5; // Maintain 5x speed
isCountdownActive = false;
countdownAcceleration = 1;
startGame();
}
}, 1000);
// Smooth acceleration during countdown
var accelerationInterval = LK.setInterval(function () {
if (!isCountdownActive) {
LK.clearInterval(accelerationInterval);
return;
}
var elapsed = Date.now() - startTime;
var progress = Math.min(elapsed / countdownDuration, 1);
// Smooth acceleration curve - starts slow, ramps up faster
var easedProgress = progress * progress;
countdownAcceleration = 1 + easedProgress * 4; // 1x to 5x speed
}, 50); // Update every 50ms for smooth acceleration
}
function showResultsScreen() {
currentGameState = GAME_STATE_RESULTS;
if (titleScreen.container) {
titleScreen.container.visible = false;
}
if (songSelectScreen.container) {
songSelectScreen.container.visible = false;
}
if (resultsScreen.container) {
resultsScreen.container.visible = true;
}
if (tutorialScreen.container) {
tutorialScreen.container.visible = false;
}
hideGameplayUI();
}
function startGame() {
currentGameState = GAME_STATE_PLAYING;
songSelectionInProgress = false; // Selection process is complete, game is starting
gameStarted = true;
gameStartTime = Date.now();
showGameplayUI();
moveScanner();
// Determine which music to play based on the selected song
var musicId = 'gameMusic'; // Default music
if (currentSongData === SongDatabase['Remember This']) {
musicId = 'rememberThis';
} else if (currentSongData === SongDatabase['Arcade Heart']) {
musicId = 'arcadeHeart';
} else if (currentSongData === SongDatabase['Runner']) {
musicId = 'runner';
}
LK.playMusic(musicId, {
loop: false
});
}
function moveScanner() {
if (!scanner || !gameStarted || currentGameState !== GAME_STATE_PLAYING) {
return;
}
tween.stop(scanner);
var targetY = scannerIsMovingUp ? SCANNER_Y_MIN : SCANNER_Y_MAX;
tween(scanner, {
y: targetY
}, {
duration: SCANNER_CYCLE_DURATION / 2,
easing: tween.linear,
onFinish: function onFinish() {
scannerIsMovingUp = !scannerIsMovingUp;
moveScanner();
}
});
}
function spawnNotesForCurrentTime(currentTime) {
if (!currentSongData) {
return;
}
currentSongData.notes.forEach(function (noteData, index) {
var noteKey = index + '_' + noteData.time;
var alreadySpawned = false;
for (var i = 0; i < spawnedNotes.length; i++) {
if (spawnedNotes[i] === noteKey) {
alreadySpawned = true;
break;
}
}
if (!alreadySpawned && currentTime >= noteData.time - NOTE_SPAWN_AHEAD_MS && currentTime <= noteData.time - NOTE_SPAWN_AHEAD_MS + 100) {
var calculatedY = calculateNotePosition(noteData.time);
// Calculate end note Y position for hold notes
var endNoteY;
if (noteData.type === 'hold' && noteData.duration > 0) {
var endTime = noteData.time + noteData.duration;
endNoteY = calculateNotePosition(endTime);
}
var calculatedX = calculateZoneX(noteData.zone, calculatedY, endNoteY);
// Check for overlapping notes and adjust X position if needed
var attempts = 0;
var maxAttempts = 10;
var noteRadius = 150; // Approximate radius to avoid overlap
while (attempts < maxAttempts) {
var hasOverlap = false;
// Check against existing active notes
for (var j = 0; j < notes.length; j++) {
var existingNote = notes[j];
if (!existingNote || !existingNote.active) {
continue;
}
var distance = Math.sqrt(Math.pow(calculatedX - existingNote.x, 2) + Math.pow(calculatedY - existingNote.y, 2));
if (distance < noteRadius) {
hasOverlap = true;
break;
}
}
if (!hasOverlap) {
break; // Good position found
}
// Try a new X position within the same zone
calculatedX = calculateZoneX(noteData.zone, calculatedY, endNoteY);
attempts++;
}
var processedNoteData = {
time: noteData.time,
type: noteData.type,
x: calculatedX,
y: calculatedY,
color: noteData.color,
duration: noteData.duration
};
var note = new Note(processedNoteData, currentTime);
notes.push(note);
game.addChild(note);
note.spawnIn();
spawnedNotes.push(noteKey);
}
});
}
function setupGame(songName) {
LK.setScore(0);
gameStarted = false;
perfectCount = 0;
goodCount = 0;
missCount = 0;
// Reset particle speed for new game
baseParticleSpeed = 1;
isCountdownActive = false;
countdownAcceleration = 1;
// Reset particle direction to downward
globalParticleDirection = {
x: 0,
y: 1
};
targetParticleDirection = {
x: 0,
y: 1
};
isChangingDirection = false;
lastDirectionChangeTime = Date.now();
nextDirectionChangeDelay = 15000 + Math.random() * 15000;
if (scoreTxt && scoreTxt.destroy) {
scoreTxt.destroy();
}
scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.setText(LK.getScore());
// createZoneIndicators(); // Removed zone indicators from background
if (scanner && scanner.destroy) {
scanner.destroy();
}
scanner = new Scanner();
scanner.y = SCANNER_Y_MAX;
game.addChild(scanner);
notes.forEach(function (note) {
if (note && note.destroy) {
note.destroy();
}
});
notes = [];
spawnedNotes = [];
currentSongData = SongDatabase[songName];
BPM = currentSongData.bpm;
BEAT_DURATION_MS = 60 / BPM * 1000;
SCANNER_CYCLE_DURATION = currentSongData.scannerCycleDuration;
SCANNER_HALF_CYCLE = SCANNER_CYCLE_DURATION / 2;
scannerIsMovingUp = true;
startCountdown();
// Reinitialize particles for proper distribution
if (backgroundParticles.length === 0) {
for (var i = 0; i < NUM_BACKGROUND_PARTICLES; i++) {
var particle = new BackgroundParticle();
// Let init() handle the positioning
backgroundParticles.push(particle);
game.addChildAt(particle, 0);
}
} else {
// Reinitialize existing particles for new distribution
backgroundParticles.forEach(function (p) {
p.init(); // init now handles random x and y
});
}
}
function checkZoneHit(x, y) {
var hitZone = x < GAME_WIDTH / 2 ? 'left' : 'right';
var currentTime = Date.now() - gameStartTime;
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
if (!note || !note.active || note.isHit || note.isSpawning || !note.noteGraphics) {
continue;
}
if (note.zone === hitZone) {
var noteCoreHeight = note.noteGraphics.height;
var noteCenterY = note.y;
var scannerY = scanner.y;
var perfectHitRadius = noteCoreHeight * PERFECT_HIT_RATIO / 2;
var goodHitRadius = noteCoreHeight / 2;
var perfectHitTop = noteCenterY - perfectHitRadius;
var perfectHitBottom = noteCenterY + perfectHitRadius;
var goodHitTop = noteCenterY - goodHitRadius;
var goodHitBottom = noteCenterY + goodHitRadius;
var accuracyText = null;
var hitPoints = 0;
var popupColor = 0xFFFFFF;
if (scannerY >= perfectHitTop && scannerY <= perfectHitBottom) {
accuracyText = "PERFECT";
popupColor = PERFECT_POPUP_COLOR;
if (note.type === 'tap') {
hitPoints = POINTS_PERFECT_TAP;
} else if (note.type === 'hold') {
hitPoints = POINTS_PERFECT_HOLD_START;
}
} else if (scannerY >= goodHitTop && scannerY <= goodHitBottom) {
accuracyText = "GOOD";
popupColor = GOOD_POPUP_COLOR;
if (note.type === 'tap') {
hitPoints = POINTS_GOOD_TAP;
} else if (note.type === 'hold') {
hitPoints = POINTS_GOOD_HOLD_START;
}
}
if (accuracyText) {
note.isHit = true;
showAccuracyPopup(accuracyText, note.x, note.y, popupColor);
if (accuracyText === "PERFECT") {
perfectCount++;
} else if (accuracyText === "GOOD") {
goodCount++;
}
if (note.type === 'tap') {
note.showHitEffect();
} else if (note.type === 'hold') {
note.startHoldEffect();
}
if (hitPoints > 0) {
LK.setScore(LK.getScore() + hitPoints);
scoreTxt.setText(LK.getScore());
}
break;
}
}
}
}
function initializeTutorialScreen() {
tutorialScreen.container = new Container();
tutorialScreen.container.visible = false;
game.addChild(tutorialScreen.container);
var bg = tutorialScreen.container.attachAsset('tutorialBg', {
anchorX: 0,
anchorY: 0
});
bg.alpha = 0.9;
bg.width = GAME_WIDTH;
bg.height = GAME_HEIGHT;
var currentY = 80;
var smallGap = 20;
var mediumGap = 40;
var largeGap = 60;
var textBlockGap = 10;
var visualOffsetY = 30; // Offset Y for visuals relative to text center
var visualScale = 0.3;
var noteVisualXLeft = GAME_WIDTH / 2 - 150;
var noteVisualXMid = GAME_WIDTH / 2;
var noteVisualXRight = GAME_WIDTH / 2 + 150;
// Title
var title = _createTutorialText("How to Play", 120, currentY, tutorialScreen.container, 0x00FFFF, 'center');
currentY += title.height + largeGap;
// Introduction
var introText = _createTutorialText("The scanner line moves up and down the screen. Notes will appear on the screen; interact with them as the scanner aligns with each note!", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'center');
currentY += introText.height + mediumGap;
// Zones & Controls
var zonesHeader = _createTutorialText("Play Zones & Controls", 80, currentY, tutorialScreen.container, 0xFFFF00, 'center');
currentY += zonesHeader.height + smallGap;
var zonesText = _createTutorialText("The screen has a LEFT zone (Blue) and a RIGHT zone (Red). Tap ANYWHERE within the correct zone when a note aligns with the scanner line. You do NOT need to tap the note itself.", 55, currentY, tutorialScreen.container, 0xFFFFFF, 'left');
currentY += zonesText.height + mediumGap;
// Tap Notes
var tapHeader = _createTutorialText("Tap Notes", 80, currentY, tutorialScreen.container, 0xFFFF00, 'center');
currentY += tapHeader.height + smallGap;
var tapDesc = _createTutorialText("Tap the zone once when the note aligns with the scanner.", 55, currentY, tutorialScreen.container, 0xFFFFFF, 'left');
currentY += tapDesc.height + textBlockGap;
var regularTapHeader = _createTutorialText("- Regular Tap Notes:", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'left');
currentY += regularTapHeader.height + textBlockGap;
var leftTapText = _createTutorialText(" Left Zone (Blue): Tap LEFT.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150);
_createTutorialNoteVisual('noteCore', COLOR_LEFT_ZONE, noteVisualXLeft, currentY + visualOffsetY, visualScale, tutorialScreen.container);
currentY += leftTapText.height + textBlockGap;
var rightTapText = _createTutorialText(" Right Zone (Red): Tap RIGHT.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150);
_createTutorialNoteVisual('noteCore', COLOR_RIGHT_ZONE, noteVisualXRight, currentY + visualOffsetY, visualScale, tutorialScreen.container);
currentY += rightTapText.height + mediumGap;
var syncTapHeader = _createTutorialText("- Synced Tap Notes (Pink):", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'left');
currentY += syncTapHeader.height + textBlockGap;
var syncTapText = _createTutorialText(" Appear on both sides. Tap BOTH zones simultaneously.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150);
currentY += syncTapText.height + mediumGap; // Space after text, before visuals
var scaledVisualHeight = 300 * visualScale; // Assuming noteCore asset height is 300px
var visualCenterYForTap = currentY + scaledVisualHeight / 2;
_createTutorialNoteVisual('noteCore', COLOR_SYNC_TAP, noteVisualXLeft, visualCenterYForTap, visualScale, tutorialScreen.container);
_createTutorialNoteVisual('noteCore', COLOR_SYNC_TAP, noteVisualXRight, visualCenterYForTap, visualScale, tutorialScreen.container);
currentY += scaledVisualHeight + largeGap; // Space after visuals line
// Hold Notes
var holdHeader = _createTutorialText("Hold Notes", 80, currentY, tutorialScreen.container, 0xFFFF00, 'center');
currentY += holdHeader.height + smallGap;
var holdDesc = _createTutorialText("Tap and HOLD for the note's trail duration. Release as the trail ends.", 55, currentY, tutorialScreen.container, 0xFFFFFF, 'left');
currentY += holdDesc.height + textBlockGap;
var regularHoldHeader = _createTutorialText("- Regular Hold Notes:", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'left');
currentY += regularHoldHeader.height + textBlockGap;
var leftHoldText = _createTutorialText(" Left Zone (Blue): Hold LEFT.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150);
_createTutorialNoteVisual('holdNoteCore', COLOR_LEFT_ZONE, noteVisualXLeft, currentY + visualOffsetY, visualScale, tutorialScreen.container);
currentY += leftHoldText.height + textBlockGap;
var rightHoldText = _createTutorialText(" Right Zone (Red): Hold RIGHT.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150);
_createTutorialNoteVisual('holdNoteCore', COLOR_RIGHT_ZONE, noteVisualXRight, currentY + visualOffsetY, visualScale, tutorialScreen.container);
currentY += rightHoldText.height + mediumGap;
var syncHoldHeader = _createTutorialText("- Synced Hold Notes (Purple):", 60, currentY, tutorialScreen.container, 0xFFFFFF, 'left');
currentY += syncHoldHeader.height + textBlockGap;
var syncHoldText = _createTutorialText(" Appear on both sides. Hold BOTH zones simultaneously.", 50, currentY, tutorialScreen.container, 0xFFFFFF, 'left', 150);
currentY += syncHoldText.height + mediumGap; // Space after text, before visuals
var scaledVisualHeight = 300 * visualScale; // Assuming holdNoteCore asset height is 300px
var visualCenterYForHold = currentY + scaledVisualHeight / 2;
_createTutorialNoteVisual('holdNoteCore', COLOR_SYNC_HOLD, noteVisualXLeft, visualCenterYForHold, visualScale, tutorialScreen.container);
_createTutorialNoteVisual('holdNoteCore', COLOR_SYNC_HOLD, noteVisualXRight, visualCenterYForHold, visualScale, tutorialScreen.container);
currentY += scaledVisualHeight + largeGap; // Space after visuals line
// Close Button
// Position close button near the bottom, ensure currentY doesn't push it off screen
var closeButtonY = Math.max(currentY + mediumGap, GAME_HEIGHT - 150);
tutorialScreen.closeButton = _createTutorialText("Tap to Close", 70, closeButtonY, tutorialScreen.container, 0xCCCCCC, 'center');
tutorialScreen.closeButton.interactive = true; // For clarity, though handled by game.down
}
function handleSongItemClick(x, y) {
if (songSelectionInProgress) {
return true; // Prevent new selections while one is processing
}
for (var i = 0; i < songSelectScreen.items.length; i++) {
var item = songSelectScreen.items[i];
// Ensure item and item.scale exist before trying to use them for tweening
if (!item || !item.scale) {
continue;
}
var itemX = item.x;
var itemY = item.y + songSelectScreen.scrollContainer.y;
// Check if the click is within the bounds of the current item
if (x >= itemX && x <= itemX + (GAME_WIDTH - 200) && y >= itemY && y <= itemY + SONG_ITEM_HEIGHT) {
songSelectionInProgress = true; // Set flag
// Stop any existing scale tweens on this item and reset scale before pulsing
tween.stop(item.scale);
item.scale.set(1.0, 1.0);
// Pulse animation: scale down (shrink)
tween(item.scale, {
x: 0.9,
y: 0.9
}, {
duration: 100,
// Duration of scale down
easing: tween.easeOut,
onFinish: function onFinish() {
// Pulse animation: scale back to normal
tween(item.scale, {
x: 1.0,
y: 1.0
}, {
duration: 100,
// Duration of scale back to normal
easing: tween.easeIn,
onFinish: function onFinish() {
// Short timeout to allow pulse to be visible before screen change
LK.setTimeout(function () {
if (songSelectScreen.container) {
songSelectScreen.container.visible = false;
}
setupGame(item.songName);
// songSelectionInProgress will be reset by startGame or other screen transitions
}, 150); // Delay before starting game setup
}
});
}
});
return true; // Song clicked and processing started
}
}
return false; // No song item was clicked
}
function initializeResultsScreen() {
resultsScreen.container = new Container();
game.addChild(resultsScreen.container);
resultsScreen.container.visible = false;
resultsScreen.title = new Text2('Results', {
size: 180,
fill: 0xFFFFFF,
stroke: 0x00FFFF,
strokeThickness: 6
});
resultsScreen.title.anchor.set(0.5, 0.5);
resultsScreen.title.x = GAME_WIDTH / 2;
resultsScreen.title.y = GAME_HEIGHT / 2 - 350;
resultsScreen.container.addChild(resultsScreen.title);
resultsScreen.scoreText = new Text2('Final Score: 0', {
size: 100,
fill: 0xFFFFFF
});
resultsScreen.scoreText.anchor.set(0.5, 0.5);
resultsScreen.scoreText.x = GAME_WIDTH / 2;
resultsScreen.scoreText.y = GAME_HEIGHT / 2 - 150;
resultsScreen.container.addChild(resultsScreen.scoreText);
resultsScreen.highScoreText = new Text2('High Score: 0', {
size: 80,
fill: 0xFFDD00
});
resultsScreen.highScoreText.anchor.set(0.5, 0.5);
resultsScreen.highScoreText.x = GAME_WIDTH / 2;
resultsScreen.highScoreText.y = GAME_HEIGHT / 2 - 50;
resultsScreen.container.addChild(resultsScreen.highScoreText);
resultsScreen.perfectText = new Text2('Perfect: 0', {
size: 70,
fill: 0x00FF00
});
resultsScreen.perfectText.anchor.set(0.5, 0.5);
resultsScreen.perfectText.x = GAME_WIDTH / 2;
resultsScreen.perfectText.y = GAME_HEIGHT / 2 + 50;
resultsScreen.container.addChild(resultsScreen.perfectText);
resultsScreen.goodText = new Text2('Good: 0', {
size: 70,
fill: 0xFFFF00
});
resultsScreen.goodText.anchor.set(0.5, 0.5);
resultsScreen.goodText.x = GAME_WIDTH / 2;
resultsScreen.goodText.y = GAME_HEIGHT / 2 + 130;
resultsScreen.container.addChild(resultsScreen.goodText);
resultsScreen.missText = new Text2('Miss: 0', {
size: 70,
fill: 0xFF0000
});
resultsScreen.missText.anchor.set(0.5, 0.5);
resultsScreen.missText.x = GAME_WIDTH / 2;
resultsScreen.missText.y = GAME_HEIGHT / 2 + 210;
resultsScreen.container.addChild(resultsScreen.missText);
resultsScreen.continueText = new Text2('Tap to Continue', {
size: 90,
fill: 0xCCCCCC
});
resultsScreen.continueText.anchor.set(0.5, 0.5);
resultsScreen.continueText.x = GAME_WIDTH / 2;
resultsScreen.continueText.y = GAME_HEIGHT / 2 + 430;
resultsScreen.container.addChild(resultsScreen.continueText);
if (resultsScreen.pulseInterval) {
LK.clearInterval(resultsScreen.pulseInterval);
}
resultsScreen.pulseInterval = LK.setInterval(function () {
if (currentGameState === GAME_STATE_RESULTS && resultsScreen.continueText) {
var pulseScale = resultsScreen.continueText.scale.x;
var pulseDirection = resultsScreen.continueText.pulseDirection || 1;
pulseScale += pulseDirection * 0.02;
if (pulseScale > 1.1) {
pulseScale = 1.1;
pulseDirection = -1;
} else if (pulseScale < 0.9) {
pulseScale = 0.9;
pulseDirection = 1;
}
resultsScreen.continueText.scale.set(pulseScale);
resultsScreen.continueText.pulseDirection = pulseDirection;
}
}, 50);
}
function showTutorialScreen() {
currentGameState = GAME_STATE_TUTORIAL;
if (titleScreen.container) {
titleScreen.container.visible = false;
}
if (songSelectScreen.container) {
songSelectScreen.container.visible = false;
}
if (resultsScreen.container) {
resultsScreen.container.visible = false;
}
if (tutorialScreen.container) {
tutorialScreen.container.visible = true;
}
hideGameplayUI();
}
initializeTitleScreen();
initializeSongSelectScreen();
initializeResultsScreen();
initializeTutorialScreen(); // Initialize the new tutorial screen
for (var i = 0; i < NUM_BACKGROUND_PARTICLES; i++) {
var particle = new BackgroundParticle();
particle.y = Math.random() * GAME_HEIGHT;
backgroundParticles.push(particle);
game.addChildAt(particle, 0);
}
showTitleScreen();
game.down = function (x, y, obj) {
if (currentGameState === GAME_STATE_TITLE) {
showSongSelectScreen();
return;
}
if (currentGameState === GAME_STATE_TUTORIAL) {
// Check click on tutorial's close button (entire screen acts as close for simplicity)
// More precise check if tutorialScreen.closeButton was an actual button object with bounds:
// var cb = tutorialScreen.closeButton;
// if (x >= cb.x - cb.width * cb.anchor.x && x <= cb.x + cb.width * (1-cb.anchor.x) &&
// y >= cb.y - cb.height * cb.anchor.y && y <= cb.y + cb.height * (1-cb.anchor.y)) {
showSongSelectScreen();
// }
return;
}
if (currentGameState === GAME_STATE_RESULTS) {
showSongSelectScreen();
return;
}
if (currentGameState === GAME_STATE_SONG_SELECT) {
// Check for tutorial button click
var tb = songSelectScreen.tutorialButton;
if (tb && x >= tb.x - tb.width * tb.anchor.x && x <= tb.x + tb.width * (1 - tb.anchor.x) && y >= tb.y - tb.height && y <= tb.y) {
// anchor is 0.5, 1
showTutorialScreen();
return;
}
if (handleSongItemClick(x, y)) {
return;
}
isDraggingSongList = true;
dragStartYSongList = y;
return;
}
if (currentGameState === GAME_STATE_PLAYING && gameStarted) {
checkZoneHit(x, y);
var hitZoneForDown = x < GAME_WIDTH / 2 ? 'left' : 'right';
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (!note.active || note.isSpawning || note.holdSuccessfullyCompleted || note.isMissed) {
continue;
}
if (note.zone === hitZoneForDown && note.isHit) {
if (note.type === 'hold' && !note.isHolding) {
note.isHolding = true;
activeHoldNotes[note.zone] = note;
}
}
}
isDragging = true;
dragStartX = x;
dragStartY = y;
}
};
game.move = function (x, y, obj) {
if (currentGameState === GAME_STATE_SONG_SELECT && isDraggingSongList) {
var deltaY = y - dragStartYSongList;
songSelectScrollY = Math.max(0, Math.min(maxScrollY, songSelectScrollY - deltaY));
songSelectScreen.scrollContainer.y = 300 - songSelectScrollY;
dragStartYSongList = y;
}
if (currentGameState === GAME_STATE_PLAYING && isDragging && gameStarted) {}
};
game.up = function (x, y, obj) {
if (currentGameState === GAME_STATE_SONG_SELECT) {
isDraggingSongList = false;
return;
}
if (currentGameState === GAME_STATE_PLAYING && gameStarted) {
var releasedZone = x < GAME_WIDTH / 2 ? 'left' : 'right';
var heldNote = activeHoldNotes[releasedZone];
if (heldNote && heldNote.isHolding) {
heldNote.isHolding = false;
delete activeHoldNotes[releasedZone];
var currentTimeMs = Date.now() - gameStartTime;
var noteExpectedEndTimeMs = heldNote.hitTime + heldNote.duration;
var absoluteEndNoteY = heldNote.y + (heldNote.endNote ? heldNote.endNote.y : 0);
var hitTimeCycle = heldNote.hitTime % SCANNER_CYCLE_DURATION;
var noteScannerMovingUp = hitTimeCycle < SCANNER_HALF_CYCLE;
var trailDirection = noteScannerMovingUp ? -1 : 1;
var scannerAtEnd;
if (trailDirection === -1) {
scannerAtEnd = scanner.y <= absoluteEndNoteY + HIT_TOLERANCE_PX_FOR_HOLD_END && scanner.y >= absoluteEndNoteY - HIT_TOLERANCE_PX_FOR_HOLD_END / 2;
} else {
scannerAtEnd = scanner.y >= absoluteEndNoteY - HIT_TOLERANCE_PX_FOR_HOLD_END && scanner.y <= absoluteEndNoteY + HIT_TOLERANCE_PX_FOR_HOLD_END / 2;
}
var timeReachedOrPassedEnd = currentTimeMs >= noteExpectedEndTimeMs - HOLD_END_GRACE_PERIOD_MS;
var timeNotTooLate = currentTimeMs <= noteExpectedEndTimeMs + HOLD_END_GRACE_PERIOD_MS + 200;
if (scannerAtEnd && timeReachedOrPassedEnd && timeNotTooLate) {
heldNote.completeHold();
LK.setScore(LK.getScore() + 50);
scoreTxt.setText(LK.getScore());
} else {
heldNote.failHold();
missCount++;
}
}
isDragging = false;
}
};
game.update = function () {
// Update background particles with new space travel effects
backgroundParticles.forEach(function (particle) {
particle.updateParticle();
});
// Handle direction changes during gameplay
if (currentGameState === GAME_STATE_PLAYING && gameStarted && !isCountdownActive) {
var currentTimeForDirectionChange = Date.now();
if (currentTimeForDirectionChange - lastDirectionChangeTime > nextDirectionChangeDelay) {
changeParticleDirection();
}
}
// Handle global particle direction changes (original code)
var currentTime = Date.now();
// This part is now handled by the block above for GAME_STATE_PLAYING
// and the general update below might be redundant or could be simplified if only for non-playing states
// For now, let's keep the existing logic structure for non-playing state direction changes or initial setup
if (!isChangingDirection && currentGameState !== GAME_STATE_PLAYING && currentTime - lastDirectionChangeTime > nextDirectionChangeDelay) {
changeParticleDirection(); // Call the unified function
}
// The following block for `if (isChangingDirection)` is now handled by `getCurrentParticleDirection`
// which is called by `particle.updateParticle()`.
// So, the direct manipulation of `globalParticleDirection` here might be redundant
// if particles are always updating based on `getCurrentParticleDirection`.
// However, `changeParticleDirection` sets `isChangingDirection = true` and `directionChangeStartTime`.
// `getCurrentParticleDirection` uses these to interpolate and then resets `isChangingDirection`.
// The logic seems okay as `getCurrentParticleDirection` will handle the smooth transition.
if (currentGameState !== GAME_STATE_PLAYING || !gameStarted) {
return;
}
var currentTime = Date.now() - gameStartTime;
spawnNotesForCurrentTime(currentTime);
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
if (!note) {
notes.splice(i, 1);
continue;
}
if (note.type === 'hold' && note.isHolding && note.active && !note.holdSuccessfullyCompleted && !note.isMissed) {
note.updateHoldEffects(scanner.y);
var currentTimeMsForUpdate = Date.now() - gameStartTime;
var noteExpectedEndTimeMsForUpdate = note.hitTime + note.duration;
if (currentTimeMsForUpdate > noteExpectedEndTimeMsForUpdate + HOLD_END_GRACE_PERIOD_MS + 500) {
if (activeHoldNotes[note.zone] === note) {
note.failHold();
delete activeHoldNotes[note.zone];
missCount++;
}
}
}
if (note.active && !note.isHit && !note.isMissed && !note.isSpawning) {
var timeDiff = currentTime - note.hitTime;
var scannerPassed = false;
if (scannerIsMovingUp && scanner.y < note.y - 50) {
scannerPassed = true;
} else if (!scannerIsMovingUp && scanner.y > note.y + 50) {
scannerPassed = true;
}
if (scannerPassed && timeDiff > 300) {
note.isMissed = true;
note.showMissEffect();
missCount++;
}
}
if (!note.active) {
notes.splice(i, 1);
if (game.children.indexOf(note) > -1) {
game.removeChild(note);
}
if (note.destroy) {
note.destroy();
}
}
}
if (currentSongData && currentTime > currentSongData.totalLength + 500 && currentGameState === GAME_STATE_PLAYING) {
LK.stopMusic();
gameStarted = false;
if (scanner) {
tween.stop(scanner);
}
var finalScore = LK.getScore();
// --- Letter Grade Calculation (MOVED HERE) ---
var totalNotes = 0;
if (currentSongData && currentSongData.notes) {
totalNotes = currentSongData.notes.length;
}
var grade = "C";
if (totalNotes > 0) {
if (missCount === 0 && perfectCount === totalNotes) {
grade = "S";
} else {
var hitCount = perfectCount + goodCount;
var ratio = hitCount / totalNotes;
if (ratio >= 0.95) {
grade = "A";
} else if (ratio >= 0.80) {
grade = "B";
} else {
grade = "C";
}
}
} else {
grade = "-";
}
var songName = null;
for (var key in SongDatabase) {
if (SongDatabase[key] === currentSongData) {
songName = key;
break;
}
}
if (songName) {
var wasUpdated = updateHighScore(songName, finalScore, grade); // Now grade is available
if (wasUpdated) {
// Update songSelectScreen items if they are already created
if (songSelectScreen.items) {
for (var j = 0; j < songSelectScreen.items.length; j++) {
var item = songSelectScreen.items[j];
if (item.songName === songName) {
// Assuming scoreText is the 4th child (index 3)
var scoreTextDisplay = item.children[3];
if (scoreTextDisplay && scoreTextDisplay.setText) {
var gradeDisplay = SongDatabase[songName].highestGrade || 'C';
scoreTextDisplay.setText('High Score: ' + SongDatabase[songName].highScore + ' | Grade: ' + gradeDisplay);
}
break;
}
}
}
}
if (resultsScreen.highScoreText) {
resultsScreen.highScoreText.setText("High Score: " + SongDatabase[songName].highScore);
}
}
if (resultsScreen.scoreText) {
resultsScreen.scoreText.setText("Final Score: " + finalScore);
}
if (resultsScreen.perfectText) {
resultsScreen.perfectText.setText("Perfect: " + perfectCount);
}
if (resultsScreen.goodText) {
resultsScreen.goodText.setText("Good: " + goodCount);
}
if (resultsScreen.missText) {
resultsScreen.missText.setText("Miss: " + missCount);
}
if (!resultsScreen.gradeText) {
resultsScreen.gradeText = new Text2('Grade: ' + grade, {
size: 120,
fill: 0x00FFFF
});
resultsScreen.gradeText.anchor.set(0.5, 0.5);
resultsScreen.gradeText.x = GAME_WIDTH / 2;
resultsScreen.gradeText.y = GAME_HEIGHT / 2 + 280;
resultsScreen.container.addChild(resultsScreen.gradeText);
} else {
resultsScreen.gradeText.setText('Grade: ' + grade);
resultsScreen.gradeText.visible = true;
}
showResultsScreen();
}
if (scanner && game.children.indexOf(scanner) > -1) {
game.removeChild(scanner);
game.addChild(scanner);
}
};
The word 'Pulsar' in a glowing neon SVG in futuristic font. The word is half blue on the left and half red on the right. In-Game asset. 2d. High contrast. No shadows
Remove the background.
A thin expanding ring with energy distortion ``` - Outer ring: 4-6 pixels thick, bright cyan (#00FFFF) - Inner ring: 2-3 pixels thick, white (#FFFFFF) - Ring thickness: Tapers from thick to thin as it expands - Transparency: Ring itself at 80% opacity - Background: Completely transparent - Edge treatment: Soft anti-aliased edges, slight glow effect - Optional: Subtle "energy crackle" texture within the ring. In-Game asset. 2d. High contrast. No shadows
Soft, lingering light effect ``` - Center: Warm orange (#FF6600) at 40% opacity - Middle: Yellow (#FFAA00) at 25% opacity - Edge: Transparent - Shape: Perfect circle with very soft, wide falloff. In-Game asset. 2d. High contrast. No shadows