/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
var facekit = LK.import("@upit/facekit.v1");
/**** 
* Classes
****/ 
var BackgroundGrid = Container.expand(function () {
	var self = Container.call(this);
	// Create horizontal grid lines
	self.horizontalLines = [];
	for (var i = 0; i < 15; i++) {
		var line = self.attachAsset('gridLine', {
			anchorX: 0,
			anchorY: 0.5,
			alpha: 0.8
		});
		line.y = i * 200 - 400;
		line.tint = 0x00FFFF; // Start with bright cyan
		self.horizontalLines.push(line);
	}
	// Create vertical grid lines
	self.verticalLines = [];
	for (var j = 0; j < 8; j++) {
		var vLine = self.attachAsset('gridLineVertical', {
			anchorX: 0.5,
			anchorY: 0,
			alpha: 0.7
		});
		vLine.x = j * 300;
		vLine.tint = 0xFF00FF; // Start with bright magenta
		self.verticalLines.push(vLine);
	}
	self.update = function () {
		// Move horizontal lines down
		for (var i = 0; i < self.horizontalLines.length; i++) {
			var line = self.horizontalLines[i];
			line.y += 2;
			// Reset line position when it goes off screen
			if (line.y > 2800) {
				line.y = -100;
			}
			// Enhanced neon glow effect - brighter and more vibrant
			var distanceFromCenter = Math.abs(line.y - 1366);
			var maxDistance = 1366;
			var baseBrightness = 0.8; // Much brighter base
			var fadeEffect = 1 - distanceFromCenter / maxDistance;
			line.alpha = Math.max(0.4, baseBrightness * fadeEffect); // Minimum brightness of 0.4
			// Add pulsing neon colors
			var pulsePhase = (LK.ticks + i * 10) * 0.05;
			var pulseBrightness = 0.8 + 0.4 * Math.sin(pulsePhase);
			line.alpha = line.alpha * pulseBrightness;
			// Cycle through neon colors
			var colorPhase = (LK.ticks * 0.01 + i * 0.2) % (Math.PI * 2);
			if (colorPhase < Math.PI * 0.66) {
				line.tint = 0x00FFFF; // Bright cyan
			} else if (colorPhase < Math.PI * 1.33) {
				line.tint = 0xFF00FF; // Bright magenta
			} else {
				line.tint = 0xFFFF00; // Bright yellow
			}
		}
		// Animate vertical lines with neon glow
		for (var j = 0; j < self.verticalLines.length; j++) {
			var vLine = self.verticalLines[j];
			// Enhanced brightness for vertical lines
			vLine.alpha = 0.7 + 0.3 * Math.sin((LK.ticks + j * 15) * 0.03);
			// Color cycling for vertical lines
			var vColorPhase = (LK.ticks * 0.008 + j * 0.3) % (Math.PI * 2);
			if (vColorPhase < Math.PI * 0.5) {
				vLine.tint = 0x00FFFF; // Cyan
			} else if (vColorPhase < Math.PI) {
				vLine.tint = 0xFF0066; // Hot pink
			} else if (vColorPhase < Math.PI * 1.5) {
				vLine.tint = 0x66FF00; // Electric lime
			} else {
				vLine.tint = 0xFF6600; // Electric orange
			}
		}
	};
	return self;
});
var Block = Container.expand(function () {
	var self = Container.call(this);
	// Array of available block assets
	var blockAssets = ['block1', 'block2', 'block3', 'block4'];
	// Randomly select a block asset
	var selectedAsset = blockAssets[Math.floor(Math.random() * blockAssets.length)];
	var blockGraphics = self.attachAsset(selectedAsset, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.8,
		scaleY: 0.8
	});
	self.speed = 8;
	self.lane = 0;
	self.caught = false;
	// Random neon colors
	var colors = [0xff00ff, 0x00ffff, 0xffff00, 0xff0066, 0x66ff00];
	blockGraphics.tint = colors[Math.floor(Math.random() * colors.length)];
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
var BombBlock = Container.expand(function () {
	var self = Container.call(this);
	var bombGraphics = self.attachAsset('bomb', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.8,
		scaleY: 0.8
	});
	self.speed = 8;
	self.lane = 0;
	self.caught = false;
	// Distinctive red color for danger
	bombGraphics.tint = 0xff0000;
	// Add warning pulsing animation to make it stand out as dangerous
	tween(bombGraphics, {
		scaleX: 1.2,
		scaleY: 1.2
	}, {
		duration: 300,
		easing: tween.easeInOut,
		onFinish: function onFinish() {
			tween(bombGraphics, {
				scaleX: 0.8,
				scaleY: 0.8
			}, {
				duration: 300,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					// Restart the pulsing animation
					if (!self.caught) {
						tween(bombGraphics, {
							scaleX: 1.2,
							scaleY: 1.2
						}, {
							duration: 300,
							easing: tween.easeInOut
						});
					}
				}
			});
		}
	});
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
var BoosterBlock = Container.expand(function () {
	var self = Container.call(this);
	var boosterGraphics = self.attachAsset('booster', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.8,
		scaleY: 0.8
	});
	self.speed = 8;
	self.lane = 0;
	self.caught = false;
	// Distinctive golden/yellow color for booster
	boosterGraphics.tint = 0xFFD700;
	// Add pulsing animation to make it stand out
	tween(boosterGraphics, {
		scaleX: 1.0,
		scaleY: 1.0
	}, {
		duration: 500,
		easing: tween.easeInOut,
		onFinish: function onFinish() {
			tween(boosterGraphics, {
				scaleX: 0.8,
				scaleY: 0.8
			}, {
				duration: 500,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					// Restart the pulsing animation
					if (!self.caught) {
						tween(boosterGraphics, {
							scaleX: 1.0,
							scaleY: 1.0
						}, {
							duration: 500,
							easing: tween.easeInOut
						});
					}
				}
			});
		}
	});
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
var Life = Container.expand(function () {
	var self = Container.call(this);
	var heartGraphics = self.attachAsset('heart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.0,
		scaleY: 1.0
	});
	// Add neon glow effect with retrowave pink
	heartGraphics.tint = 0xff0066;
	self.setActive = function (active) {
		if (active) {
			heartGraphics.alpha = 1.0;
			heartGraphics.tint = 0xff0066; // Bright neon pink
		} else {
			heartGraphics.alpha = 0.3;
			heartGraphics.tint = 0x440022; // Dim dark pink
		}
	};
	return self;
});
var MicrophoneIcon = Container.expand(function () {
	var self = Container.call(this);
	// Create microphone icon using a shape asset
	var micGraphics = self.attachAsset('micBar', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 2.0,
		scaleY: 1.5
	});
	// Style the microphone with synthwave neon colors
	micGraphics.tint = 0x00ffcc;
	micGraphics.alpha = 0.6;
	// Audio detection state
	self.isActive = false;
	self.lastVolume = 0;
	self.update = function () {
		if (gameMode === 'microphone') {
			var currentVolume = facekit.volume;
			// Update visual state based on audio levels
			if (currentVolume > 0.3) {
				// Active state - bright glow
				if (!self.isActive) {
					self.isActive = true;
					tween(micGraphics, {
						tint: 0x00ff66,
						alpha: 1.0,
						scaleX: 2.4,
						scaleY: 1.8
					}, {
						duration: 100,
						easing: tween.easeOut
					});
				}
				// Beat detection - extra bright flash
				if (detectBeat()) {
					tween(micGraphics, {
						tint: 0xffffff,
						scaleX: 3.0,
						scaleY: 2.2
					}, {
						duration: 150,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							tween(micGraphics, {
								tint: 0x00ff66,
								scaleX: 2.4,
								scaleY: 1.8
							}, {
								duration: 200,
								easing: tween.easeIn
							});
						}
					});
				}
			} else if (currentVolume > 0.1) {
				// Medium activity - moderate glow
				if (self.isActive) {
					tween(micGraphics, {
						tint: 0x00ffcc,
						alpha: 0.8,
						scaleX: 2.2,
						scaleY: 1.6
					}, {
						duration: 200,
						easing: tween.easeInOut
					});
				}
				self.isActive = false;
			} else {
				// Inactive state - dim glow with subtle pulsing
				if (self.isActive) {
					self.isActive = false;
					tween(micGraphics, {
						tint: 0x004466,
						alpha: 0.5,
						scaleX: 2.0,
						scaleY: 1.5
					}, {
						duration: 300,
						easing: tween.easeOut
					});
				}
				// Subtle pulsing to show mic is available
				var pulsePhase = LK.ticks * 0.02;
				micGraphics.alpha = 0.4 + 0.2 * Math.sin(pulsePhase);
			}
			self.lastVolume = currentVolume;
		}
	};
	return self;
});
var Ship = Container.expand(function (shipType) {
	var self = Container.call(this);
	// Use the provided shipType or default to classicShip
	var assetType = shipType || 'classicShip';
	var shipGraphics = self.attachAsset(assetType, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 3.0,
		scaleY: 3.0
	});
	// Add glow effect
	shipGraphics.filters = [];
	self.currentLane = 1; // 0 = left, 1 = center, 2 = right
	self.targetX = 1024; // center position
	self.update = function () {
		// Smooth movement to target lane
		var diff = self.targetX - self.x;
		if (Math.abs(diff) > 2) {
			self.x += diff * 0.15;
		} else {
			self.x = self.targetX;
		}
	};
	self.moveToLane = function (lane) {
		self.currentLane = lane;
		if (lane === 0) {
			self.targetX = 341; // left lane
		} else if (lane === 1) {
			self.targetX = 1024; // center lane
		} else if (lane === 2) {
			self.targetX = 1707; // right lane
		}
		// Add movement animation
		tween(shipGraphics, {
			scaleX: 3.6,
			scaleY: 2.4
		}, {
			duration: 100,
			onFinish: function onFinish() {
				tween(shipGraphics, {
					scaleX: 3.0,
					scaleY: 3.0
				}, {
					duration: 100
				});
			}
		});
	};
	return self;
});
var UnlockableShip = Container.expand(function (shipData) {
	var self = Container.call(this);
	// Use ship data to create the ship graphics
	var shipGraphics = self.attachAsset(shipData.assetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 2.0,
		scaleY: 2.0
	});
	// Apply the ship's unique color
	shipGraphics.tint = shipData.color;
	// Store ship properties
	self.shipData = shipData;
	self.extraLives = shipData.extraLives;
	// Add glow effect for unlocked ships
	self.addGlowEffect = function () {
		tween(shipGraphics, {
			alpha: 1.2
		}, {
			duration: 500,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(shipGraphics, {
					alpha: 0.8
				}, {
					duration: 500,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						self.addGlowEffect();
					}
				});
			}
		});
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x0a0a0a
});
/**** 
* Game Code
****/ 
// Create synthwave background with gradient effect
game.setBackgroundColor(0x270050);
// Create moving background grid
var backgroundGrid = game.addChild(new BackgroundGrid());
// Array of synthwave tracks for classic mode
var synthwaveTracks = ['synthwave1', 'synthwave2', 'synthwave3', 'lofitrack', 'retrowave'];
// Ship unlocking system
var unlockedShips = storage.unlockedShips || [];
var availableShipTypes = ['ship1', 'ship2', 'ship3', 'ship4', 'ship5'];
var shipColors = [0xff0066, 0x00ffcc, 0xffcc00, 0x66ff00, 0xcc00ff];
var shipNames = ['Neon Striker', 'Cyber Cruiser', 'Solar Surfer', 'Plasma Rider', 'Void Walker'];
// Generate random ship data
function generateRandomShip() {
	var randomIndex = Math.floor(Math.random() * availableShipTypes.length);
	var baseColor = shipColors[randomIndex];
	// Add some randomization to the color
	var colorVariation = Math.floor(Math.random() * 0x333333);
	var finalColor = baseColor + colorVariation & 0xffffff;
	return {
		id: 'ship_' + Date.now() + '_' + Math.floor(Math.random() * 1000),
		assetId: availableShipTypes[randomIndex],
		color: finalColor,
		name: shipNames[randomIndex] + ' MK-' + (Math.floor(Math.random() * 9) + 1),
		extraLives: 1,
		unlocked: true
	};
}
// Current selected ship
var currentShipData = null;
var currentTrackIndex = 0; // Index of currently playing track
var completedTracks = []; // Array to track which tracks have been completed
var musicStartTime = 0; // Time when current music track started
var trackDuration = 60000; // Approximate track duration in milliseconds (60 seconds)
// Game state
var gameMode = 'menu'; // 'menu', 'classic', 'microphone'
var ship;
var blocks = [];
var score = 0;
var combo = 0;
var bestCombo = 0;
var lives = 3;
var maxLives = 3;
var lifeDisplays = [];
var lastSpawnTime = 0;
var spawnInterval = 1000; // 1 second
var gameSpeed = 1.0; // Speed multiplier for the game
var baseBlockSpeed = 8; // Base speed for blocks
var currentMusicTrack = null; // Track current playing music
// Beat detection variables
var audioBuffer = [];
var beatThreshold = 0.4;
var lastBeatTime = 0;
var minBeatInterval = 200; // Minimum ms between beats
var volumeHistory = [];
var bufferSize = 10;
var beatSensitivity = 1.5;
// Lane positions - equal width lanes
var lanePositions = [341, 1024, 1707];
// UI Elements
var scoreTxt = new Text2('Score: 0', {
	size: 60,
	fill: 0x00FFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 50;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var comboTxt = new Text2('Combo: 0', {
	size: 50,
	fill: 0xFF00FF
});
comboTxt.anchor.set(0, 0);
comboTxt.x = 50;
comboTxt.y = 120;
LK.gui.topLeft.addChild(comboTxt);
// Create life display hearts in top right
for (var lifeIndex = 0; lifeIndex < maxLives; lifeIndex++) {
	var lifeHeart = new Life();
	lifeHeart.x = -80 - lifeIndex * 80; // Position from right edge
	lifeHeart.y = 60;
	lifeHeart.setActive(true);
	lifeDisplays.push(lifeHeart);
	LK.gui.topRight.addChild(lifeHeart);
}
// Create menu window frame with neon border
var menuFrameBorder = LK.getAsset('menuFrameBorder', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0.6
});
menuFrameBorder.x = 0;
menuFrameBorder.y = -100;
LK.gui.center.addChild(menuFrameBorder);
// Create semi-transparent background panel
var menuFrame = LK.getAsset('menuFrame', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0.8
});
menuFrame.x = 0;
menuFrame.y = -100;
LK.gui.center.addChild(menuFrame);
// Add pulsing animation to border
tween(menuFrameBorder, {
	alpha: 0.8
}, {
	duration: 1000,
	easing: tween.easeInOut,
	onFinish: function onFinish() {
		tween(menuFrameBorder, {
			alpha: 0.4
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				// Restart the pulsing animation
				tween(menuFrameBorder, {
					alpha: 0.8
				}, {
					duration: 1000,
					easing: tween.easeInOut
				});
			}
		});
	}
});
// Create mode selection buttons with neon glow outline
var classicButton = new Text2('1. CLASSIC MODE\nBuilt-in synthwave music', {
	size: 60,
	fill: 0x00FFFF,
	stroke: 0x00FFFF,
	strokeThickness: 3
});
classicButton.anchor.set(0.5, 0.5);
classicButton.x = 0;
classicButton.y = -200;
LK.gui.center.addChild(classicButton);
var micButton = new Text2('2. MICROPHONE MODE\nSync with your music', {
	size: 60,
	fill: 0xFF00FF,
	stroke: 0xFF00FF,
	strokeThickness: 3
});
micButton.anchor.set(0.5, 0.5);
micButton.x = 0;
micButton.y = -50;
LK.gui.center.addChild(micButton);
var instructionTxt = new Text2('TAP A BUTTON TO SELECT MODE', {
	size: 50,
	fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.y = 150;
LK.gui.center.addChild(instructionTxt);
// Ship unlock UI elements (initially hidden)
var unlockFrameBorder = LK.getAsset('unlockBorder', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0
});
unlockFrameBorder.x = 0;
unlockFrameBorder.y = 0;
LK.gui.center.addChild(unlockFrameBorder);
var unlockFrame = LK.getAsset('unlockFrame', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0
});
unlockFrame.x = 0;
unlockFrame.y = 0;
LK.gui.center.addChild(unlockFrame);
var unlockTitleTxt = new Text2('SHIP UNLOCKED!', {
	size: 60,
	fill: 0x00FFFF
});
unlockTitleTxt.anchor.set(0.5, 0.5);
unlockTitleTxt.x = 0;
unlockTitleTxt.y = -120;
unlockTitleTxt.alpha = 0;
LK.gui.center.addChild(unlockTitleTxt);
var unlockDescTxt = new Text2('', {
	size: 40,
	fill: 0xFFFFFF
});
unlockDescTxt.anchor.set(0.5, 0.5);
unlockDescTxt.x = 0;
unlockDescTxt.y = -60;
unlockDescTxt.alpha = 0;
LK.gui.center.addChild(unlockDescTxt);
var unlockShipDisplay = null;
var unlockContinueTxt = new Text2('TAP TO CONTINUE', {
	size: 50,
	fill: 0xFF00FF
});
unlockContinueTxt.anchor.set(0.5, 0.5);
unlockContinueTxt.x = 0;
unlockContinueTxt.y = 120;
unlockContinueTxt.alpha = 0;
LK.gui.center.addChild(unlockContinueTxt);
// Create microphone icon (initially hidden)
var microphoneIcon = new MicrophoneIcon();
microphoneIcon.x = -80;
microphoneIcon.y = 200;
microphoneIcon.visible = false;
LK.gui.topRight.addChild(microphoneIcon);
// Create camera disable button
var cameraButton = new Text2('CAM', {
	size: 40,
	fill: 0x00ffff,
	stroke: 0x00ffff,
	strokeThickness: 2
});
cameraButton.anchor.set(0.5, 0.5);
cameraButton.x = -80;
cameraButton.y = 300;
cameraButton.visible = false;
LK.gui.topRight.addChild(cameraButton);
// Camera state tracking
var cameraEnabled = true;
// Create lane dividers
var lane1 = game.addChild(LK.getAsset('lane1', {
	x: 682,
	y: 0
}));
var lane2 = game.addChild(LK.getAsset('lane2', {
	x: 1366,
	y: 0
}));
// Create ship
ship = game.addChild(new Ship());
ship.x = 1024;
ship.y = 2400;
function startGame(mode) {
	gameMode = mode;
	score = 0;
	combo = 0;
	bestCombo = 0;
	// Calculate lives based on current ship
	var baseLives = 3;
	var extraLives = currentShipData ? currentShipData.extraLives : 0;
	lives = baseLives + extraLives;
	maxLives = lives;
	blocks = [];
	lastSpawnTime = 0;
	gameSpeed = 1.0; // Reset game speed
	currentTrackIndex = 0; // Reset track progression
	completedTracks = []; // Reset completed tracks
	musicStartTime = 0; // Reset music timer
	// Reset and update life display for new max lives
	// Remove existing life displays
	for (var i = 0; i < lifeDisplays.length; i++) {
		lifeDisplays[i].destroy();
	}
	lifeDisplays = [];
	// Create new life displays based on current max lives
	for (var lifeIndex = 0; lifeIndex < maxLives; lifeIndex++) {
		var lifeHeart = new Life();
		lifeHeart.x = -80 - lifeIndex * 80;
		lifeHeart.y = 60;
		lifeHeart.setActive(true);
		lifeDisplays.push(lifeHeart);
		LK.gui.topRight.addChild(lifeHeart);
	}
	// Reset beat detection variables
	audioBuffer = [];
	volumeHistory = [];
	lastBeatTime = 0;
	// Hide menu elements
	classicButton.visible = false;
	micButton.visible = false;
	instructionTxt.visible = false;
	menuFrame.visible = false;
	menuFrameBorder.visible = false;
	// Destroy existing ship and create new one with appropriate asset
	if (ship) {
		ship.destroy();
	}
	// Create ship with mode-specific asset
	if (mode === 'classic') {
		ship = game.addChild(new Ship('classicShip'));
	} else {
		ship = game.addChild(new Ship('microphoneShip'));
	}
	ship.x = 1024;
	ship.y = 2400;
	// Start background music only in classic mode
	if (mode === 'classic') {
		// Shuffle the playlist for randomized track order
		for (var i = synthwaveTracks.length - 1; i > 0; i--) {
			var j = Math.floor(Math.random() * (i + 1));
			var temp = synthwaveTracks[i];
			synthwaveTracks[i] = synthwaveTracks[j];
			synthwaveTracks[j] = temp;
		}
		// Start with first track in shuffled sequence
		currentMusicTrack = synthwaveTracks[currentTrackIndex];
		LK.playMusic(currentMusicTrack);
		musicStartTime = Date.now(); // Track when music started using current time
		// Hide microphone icon and camera button in classic mode
		microphoneIcon.visible = false;
		cameraButton.visible = false;
	} else {
		// Stop background music in microphone mode to focus on external audio
		currentMusicTrack = null;
		LK.stopMusic();
		// Facekit plugin automatically handles microphone access when volume is accessed
		// No initialization needed - just use facekit.volume for beat detection
		// Show microphone icon and camera button in microphone mode
		microphoneIcon.visible = true;
		cameraButton.visible = true;
		// Reset camera state when starting microphone mode
		cameraEnabled = true;
		cameraButton.setText('CAM');
		cameraButton.fill = 0x00ffff;
		cameraButton.stroke = 0x00ffff;
	}
	updateUI();
}
function spawnBlock() {
	var block;
	var random = Math.random();
	// 10% chance to spawn a bomb block
	if (random < 0.10) {
		block = new BombBlock();
		// 15% chance to spawn a booster block  
	} else if (random < 0.25) {
		block = new BoosterBlock();
	} else {
		block = new Block();
	}
	var lane;
	if (gameMode === 'microphone') {
		// Create more musical patterns based on audio intensity
		var intensity = facekit.volume;
		if (intensity > 0.8) {
			// High intensity - spawn in multiple lanes or center
			lane = Math.random() > 0.5 ? 1 : Math.floor(Math.random() * 3);
		} else if (intensity > 0.5) {
			// Medium intensity - prefer outer lanes
			lane = Math.random() > 0.5 ? 0 : 2;
		} else {
			// Low intensity - single random lane
			lane = Math.floor(Math.random() * 3);
		}
	} else {
		// Classic mode - random lane
		lane = Math.floor(Math.random() * 3);
	}
	block.lane = lane;
	block.x = lanePositions[lane];
	block.y = -50;
	block.speed = baseBlockSpeed * gameSpeed; // Apply game speed multiplier
	blocks.push(block);
	game.addChild(block);
}
function updateUI() {
	scoreTxt.setText('Score: ' + score);
	comboTxt.setText('Combo: ' + combo + ' (Best: ' + bestCombo + ')');
}
function checkCollisions() {
	for (var i = blocks.length - 1; i >= 0; i--) {
		var block = blocks[i];
		// Check if block is in ship's catch zone
		if (!block.caught && block.y >= ship.y - 100 && block.y <= ship.y + 100) {
			if (block.lane === ship.currentLane) {
				// Block caught!
				block.caught = true;
				// Check if it's a bomb block
				if (block instanceof BombBlock) {
					// Bomb effects - lose 2 lives and reset combo
					lives -= 2;
					combo = 0;
					// Update life display for lost lives
					for (var lifeIdx = Math.max(0, lives); lifeIdx < Math.min(lives + 2, lifeDisplays.length); lifeIdx++) {
						lifeDisplays[lifeIdx].setActive(false);
						// Add dramatic life loss animation - capture lifeIdx in closure
						(function (capturedIdx) {
							tween(lifeDisplays[capturedIdx], {
								scaleX: 2.0,
								scaleY: 2.0
							}, {
								duration: 300,
								onFinish: function onFinish() {
									tween(lifeDisplays[capturedIdx], {
										scaleX: 1.0,
										scaleY: 1.0
									}, {
										duration: 300
									});
								}
							});
						})(lifeIdx);
					}
					// Dramatic visual feedback for bomb
					LK.effects.flashScreen(0xff0000, 800);
					LK.effects.flashObject(ship, 0xff0000, 800);
					// Play miss sound for bomb hit
					LK.getSound('miss').play();
					// Check for game over
					if (lives <= 0) {
						// Unlock a new ship before showing game over
						var newShip = unlockNewShip();
						currentShipData = newShip;
						// Delay game over to show ship unlock
						LK.setTimeout(function () {
							LK.showGameOver();
						}, 3000);
						return;
					}
					// Check if it's a booster block
				} else if (block instanceof BoosterBlock) {
					// Booster effects
					score += 25 + combo * 3; // More points for booster
					combo += 2; // Extra combo bonus
					// Increase game speed (cap at 2.5x)
					gameSpeed = Math.min(gameSpeed + 0.2, 2.5);
					// Apply speed to all existing blocks
					for (var j = 0; j < blocks.length; j++) {
						blocks[j].speed = baseBlockSpeed * gameSpeed;
					}
					// Restart music with faster tempo (only in classic mode)
					if (gameMode === 'classic' && currentMusicTrack) {
						LK.stopMusic();
						// Small delay before restarting music to avoid audio glitches
						LK.setTimeout(function () {
							LK.playMusic(currentMusicTrack);
						}, 50);
					}
					// Special visual feedback for booster
					LK.effects.flashScreen(0xFFD700, 300);
					LK.effects.flashObject(ship, 0xFFD700, 500);
					// Play layered synthwave sounds for booster
					LK.getSound('synthBass').play();
					LK.setTimeout(function () {
						LK.getSound('synthLead').play();
					}, 100);
				} else {
					// Regular block
					score += 10 + combo * 2;
					combo++;
				}
				if (combo > bestCombo) {
					bestCombo = combo;
				}
				// Visual feedback
				LK.effects.flashObject(block, 0xffffff, 200);
				tween(block, {
					scaleX: 1.5,
					scaleY: 1.5,
					alpha: 0
				}, {
					duration: 200
				});
				// Play musical sound that matches the current track
				var trackSounds = {
					'synthwave1': ['synthBass', 'synthLead', 'synthDrum', 'synthChord'],
					'synthwave2': ['synthLead', 'synthChord', 'synthBass', 'synthDrum'],
					'synthwave3': ['synthDrum', 'synthBass', 'synthLead', 'synthChord'],
					'lofitrack': ['synthBass', 'synthChord'],
					'retrowave': ['synthLead', 'synthDrum', 'synthChord']
				};
				var soundsForTrack = trackSounds[currentMusicTrack] || ['synthBass', 'synthLead', 'synthDrum', 'synthChord'];
				// Calculate beat position based on music timing to stay in rhythm
				var baseBPM = 120;
				var currentBPM = baseBPM * gameSpeed;
				var beatLength = 60000 / currentBPM; // Beat duration in ms
				var timeElapsed = Date.now() - musicStartTime;
				var beatPosition = Math.floor(timeElapsed / beatLength % soundsForTrack.length);
				var rhythmicSound = soundsForTrack[beatPosition];
				LK.getSound(rhythmicSound).play();
				updateUI();
				// Remove block
				block.destroy();
				blocks.splice(i, 1);
				continue;
			}
		}
		// Check if block missed (passed ship)
		if (!block.caught && block.y > ship.y + 150) {
			if (block.lane === ship.currentLane) {
				// Block missed - lose life and reset combo
				lives--;
				combo = 0;
				// Update life display
				if (lives >= 0 && lives < lifeDisplays.length) {
					var currentLifeIndex = lives; // Capture current lives value
					lifeDisplays[currentLifeIndex].setActive(false);
					// Add life loss animation
					tween(lifeDisplays[currentLifeIndex], {
						scaleX: 1.5,
						scaleY: 1.5
					}, {
						duration: 200,
						onFinish: function onFinish() {
							tween(lifeDisplays[currentLifeIndex], {
								scaleX: 1.0,
								scaleY: 1.0
							}, {
								duration: 200
							});
						}
					});
				}
				LK.effects.flashScreen(0xff0000, 300);
				LK.getSound('miss').play();
				// Check for game over
				if (lives <= 0) {
					LK.showGameOver();
					return;
				}
				updateUI();
			}
			block.caught = true; // Mark as processed
		}
		// Remove blocks that are off screen
		if (block.y > 2800) {
			block.destroy();
			blocks.splice(i, 1);
		}
	}
}
function showShipUnlock(newShipData) {
	// Show unlock frame with animation
	tween(unlockFrameBorder, {
		alpha: 0.8
	}, {
		duration: 300
	});
	tween(unlockFrame, {
		alpha: 0.9
	}, {
		duration: 300
	});
	tween(unlockTitleTxt, {
		alpha: 1
	}, {
		duration: 300
	});
	// Update description text
	unlockDescTxt.setText(newShipData.name + '\n+1 Extra Life');
	tween(unlockDescTxt, {
		alpha: 1
	}, {
		duration: 300
	});
	// Create and display the unlocked ship
	if (unlockShipDisplay) {
		unlockShipDisplay.destroy();
	}
	unlockShipDisplay = new UnlockableShip(newShipData);
	unlockShipDisplay.x = 0;
	unlockShipDisplay.y = 20;
	LK.gui.center.addChild(unlockShipDisplay);
	unlockShipDisplay.addGlowEffect();
	tween(unlockContinueTxt, {
		alpha: 1
	}, {
		duration: 300
	});
	// Add pulsing animation to continue text
	tween(unlockContinueTxt, {
		scaleX: 1.1,
		scaleY: 1.1
	}, {
		duration: 800,
		easing: tween.easeInOut,
		onFinish: function onFinish() {
			tween(unlockContinueTxt, {
				scaleX: 1.0,
				scaleY: 1.0
			}, {
				duration: 800,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(unlockContinueTxt, {
						scaleX: 1.1,
						scaleY: 1.1
					}, {
						duration: 800,
						easing: tween.easeInOut
					});
				}
			});
		}
	});
}
function hideShipUnlock() {
	tween(unlockFrameBorder, {
		alpha: 0
	}, {
		duration: 300
	});
	tween(unlockFrame, {
		alpha: 0
	}, {
		duration: 300
	});
	tween(unlockTitleTxt, {
		alpha: 0
	}, {
		duration: 300
	});
	tween(unlockDescTxt, {
		alpha: 0
	}, {
		duration: 300
	});
	tween(unlockContinueTxt, {
		alpha: 0
	}, {
		duration: 300
	});
	if (unlockShipDisplay) {
		tween(unlockShipDisplay, {
			alpha: 0
		}, {
			duration: 300,
			onFinish: function onFinish() {
				unlockShipDisplay.destroy();
				unlockShipDisplay = null;
			}
		});
	}
}
function unlockNewShip() {
	// Generate a new random ship
	var newShip = generateRandomShip();
	// Add to unlocked ships
	unlockedShips.push(newShip);
	// Keep only the 5 most recent ships
	if (unlockedShips.length > 5) {
		unlockedShips = unlockedShips.slice(-5);
	}
	// Save to storage
	storage.unlockedShips = unlockedShips;
	// Show unlock animation
	showShipUnlock(newShip);
	return newShip;
}
function progressToNextTrack() {
	if (gameMode !== 'classic') {
		return;
	}
	// Mark current track as completed
	if (completedTracks.indexOf(synthwaveTracks[currentTrackIndex]) === -1) {
		completedTracks.push(synthwaveTracks[currentTrackIndex]);
	}
	// Move to next track
	currentTrackIndex++;
	// Check if all tracks have been completed
	if (currentTrackIndex >= synthwaveTracks.length) {
		// Unlock a new ship before showing victory
		var newShip = unlockNewShip();
		currentShipData = newShip;
		// Delay victory screen to show ship unlock
		LK.setTimeout(function () {
			LK.showYouWin();
		}, 3000);
		return;
	}
	// Play next track
	currentMusicTrack = synthwaveTracks[currentTrackIndex];
	LK.playMusic(currentMusicTrack);
	musicStartTime = Date.now(); // Reset music timer using current time
}
function detectBeat() {
	var currentVolume = facekit.volume;
	var currentTime = Date.now();
	// Add current volume to history buffer
	volumeHistory.push(currentVolume);
	if (volumeHistory.length > bufferSize) {
		volumeHistory.shift();
	}
	// Calculate average volume from buffer
	var avgVolume = 0;
	for (var i = 0; i < volumeHistory.length; i++) {
		avgVolume += volumeHistory[i];
	}
	avgVolume = avgVolume / volumeHistory.length;
	// Detect beat: current volume significantly higher than average
	var volumeSpike = currentVolume > avgVolume * beatSensitivity;
	var timeSinceLastBeat = currentTime - lastBeatTime;
	var beatDetected = volumeSpike && currentVolume > beatThreshold && timeSinceLastBeat > minBeatInterval;
	if (beatDetected) {
		lastBeatTime = currentTime;
		// Add visual feedback for beat detection
		LK.effects.flashScreen(0x440088, 100);
		return true;
	}
	return false;
}
function shouldSpawnBlock() {
	if (gameMode === 'microphone') {
		// Spawn based on beat detection from microphone input
		return detectBeat();
	} else {
		// Classic mode - spawn every second
		return LK.ticks - lastSpawnTime >= spawnInterval / (1000 / 60);
	}
}
// Button event handlers
classicButton.down = function (x, y, obj) {
	if (gameMode === 'menu') {
		// Add button press animation
		tween(classicButton, {
			scaleX: 1.1,
			scaleY: 1.1
		}, {
			duration: 100,
			onFinish: function onFinish() {
				tween(classicButton, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100
				});
			}
		});
		startGame('classic');
	}
};
micButton.down = function (x, y, obj) {
	if (gameMode === 'menu') {
		// Add button press animation
		tween(micButton, {
			scaleX: 1.1,
			scaleY: 1.1
		}, {
			duration: 100,
			onFinish: function onFinish() {
				tween(micButton, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100
				});
			}
		});
		startGame('microphone');
	}
};
// Camera button event handler
cameraButton.down = function (x, y, obj) {
	if (gameMode === 'microphone') {
		// Toggle camera state
		cameraEnabled = !cameraEnabled;
		// Update button appearance based on state
		if (cameraEnabled) {
			cameraButton.setText('CAM');
			cameraButton.fill = 0x00ffff;
			cameraButton.stroke = 0x00ffff;
		} else {
			cameraButton.setText('CAM\nOFF');
			cameraButton.fill = 0xff0066;
			cameraButton.stroke = 0xff0066;
		}
		// Add button press animation
		tween(cameraButton, {
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 100,
			onFinish: function onFinish() {
				tween(cameraButton, {
					scaleX: 1.0,
					scaleY: 1.0
				}, {
					duration: 100
				});
			}
		});
		// Visual feedback
		LK.effects.flashObject(cameraButton, 0xffffff, 200);
	}
};
// Touch controls for lane switching during gameplay
game.down = function (x, y, obj) {
	if (gameMode === 'menu') {
		return;
	}
	// Check if unlock screen is visible
	if (unlockFrame.alpha > 0) {
		hideShipUnlock();
		return;
	}
	// Lane switching
	if (x < 1024) {
		// Left side tapped - move left
		if (ship.currentLane > 0) {
			ship.moveToLane(ship.currentLane - 1);
		}
	} else {
		// Right side tapped - move right
		if (ship.currentLane < 2) {
			ship.moveToLane(ship.currentLane + 1);
		}
	}
};
// Main game update
game.update = function () {
	if (gameMode === 'menu') {
		// Hide microphone icon and camera button in menu
		microphoneIcon.visible = false;
		cameraButton.visible = false;
		return;
	}
	// Check for track progression in classic mode
	if (gameMode === 'classic' && musicStartTime > 0) {
		var currentTime = Date.now();
		var timeElapsed = currentTime - musicStartTime;
		// Check if current track duration has been reached
		if (timeElapsed >= trackDuration) {
			progressToNextTrack();
		}
	}
	// Spawn blocks
	if (shouldSpawnBlock()) {
		spawnBlock();
		lastSpawnTime = LK.ticks;
	}
	// Check collisions
	checkCollisions();
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
var facekit = LK.import("@upit/facekit.v1");
/**** 
* Classes
****/ 
var BackgroundGrid = Container.expand(function () {
	var self = Container.call(this);
	// Create horizontal grid lines
	self.horizontalLines = [];
	for (var i = 0; i < 15; i++) {
		var line = self.attachAsset('gridLine', {
			anchorX: 0,
			anchorY: 0.5,
			alpha: 0.8
		});
		line.y = i * 200 - 400;
		line.tint = 0x00FFFF; // Start with bright cyan
		self.horizontalLines.push(line);
	}
	// Create vertical grid lines
	self.verticalLines = [];
	for (var j = 0; j < 8; j++) {
		var vLine = self.attachAsset('gridLineVertical', {
			anchorX: 0.5,
			anchorY: 0,
			alpha: 0.7
		});
		vLine.x = j * 300;
		vLine.tint = 0xFF00FF; // Start with bright magenta
		self.verticalLines.push(vLine);
	}
	self.update = function () {
		// Move horizontal lines down
		for (var i = 0; i < self.horizontalLines.length; i++) {
			var line = self.horizontalLines[i];
			line.y += 2;
			// Reset line position when it goes off screen
			if (line.y > 2800) {
				line.y = -100;
			}
			// Enhanced neon glow effect - brighter and more vibrant
			var distanceFromCenter = Math.abs(line.y - 1366);
			var maxDistance = 1366;
			var baseBrightness = 0.8; // Much brighter base
			var fadeEffect = 1 - distanceFromCenter / maxDistance;
			line.alpha = Math.max(0.4, baseBrightness * fadeEffect); // Minimum brightness of 0.4
			// Add pulsing neon colors
			var pulsePhase = (LK.ticks + i * 10) * 0.05;
			var pulseBrightness = 0.8 + 0.4 * Math.sin(pulsePhase);
			line.alpha = line.alpha * pulseBrightness;
			// Cycle through neon colors
			var colorPhase = (LK.ticks * 0.01 + i * 0.2) % (Math.PI * 2);
			if (colorPhase < Math.PI * 0.66) {
				line.tint = 0x00FFFF; // Bright cyan
			} else if (colorPhase < Math.PI * 1.33) {
				line.tint = 0xFF00FF; // Bright magenta
			} else {
				line.tint = 0xFFFF00; // Bright yellow
			}
		}
		// Animate vertical lines with neon glow
		for (var j = 0; j < self.verticalLines.length; j++) {
			var vLine = self.verticalLines[j];
			// Enhanced brightness for vertical lines
			vLine.alpha = 0.7 + 0.3 * Math.sin((LK.ticks + j * 15) * 0.03);
			// Color cycling for vertical lines
			var vColorPhase = (LK.ticks * 0.008 + j * 0.3) % (Math.PI * 2);
			if (vColorPhase < Math.PI * 0.5) {
				vLine.tint = 0x00FFFF; // Cyan
			} else if (vColorPhase < Math.PI) {
				vLine.tint = 0xFF0066; // Hot pink
			} else if (vColorPhase < Math.PI * 1.5) {
				vLine.tint = 0x66FF00; // Electric lime
			} else {
				vLine.tint = 0xFF6600; // Electric orange
			}
		}
	};
	return self;
});
var Block = Container.expand(function () {
	var self = Container.call(this);
	// Array of available block assets
	var blockAssets = ['block1', 'block2', 'block3', 'block4'];
	// Randomly select a block asset
	var selectedAsset = blockAssets[Math.floor(Math.random() * blockAssets.length)];
	var blockGraphics = self.attachAsset(selectedAsset, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.8,
		scaleY: 0.8
	});
	self.speed = 8;
	self.lane = 0;
	self.caught = false;
	// Random neon colors
	var colors = [0xff00ff, 0x00ffff, 0xffff00, 0xff0066, 0x66ff00];
	blockGraphics.tint = colors[Math.floor(Math.random() * colors.length)];
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
var BombBlock = Container.expand(function () {
	var self = Container.call(this);
	var bombGraphics = self.attachAsset('bomb', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.8,
		scaleY: 0.8
	});
	self.speed = 8;
	self.lane = 0;
	self.caught = false;
	// Distinctive red color for danger
	bombGraphics.tint = 0xff0000;
	// Add warning pulsing animation to make it stand out as dangerous
	tween(bombGraphics, {
		scaleX: 1.2,
		scaleY: 1.2
	}, {
		duration: 300,
		easing: tween.easeInOut,
		onFinish: function onFinish() {
			tween(bombGraphics, {
				scaleX: 0.8,
				scaleY: 0.8
			}, {
				duration: 300,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					// Restart the pulsing animation
					if (!self.caught) {
						tween(bombGraphics, {
							scaleX: 1.2,
							scaleY: 1.2
						}, {
							duration: 300,
							easing: tween.easeInOut
						});
					}
				}
			});
		}
	});
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
var BoosterBlock = Container.expand(function () {
	var self = Container.call(this);
	var boosterGraphics = self.attachAsset('booster', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.8,
		scaleY: 0.8
	});
	self.speed = 8;
	self.lane = 0;
	self.caught = false;
	// Distinctive golden/yellow color for booster
	boosterGraphics.tint = 0xFFD700;
	// Add pulsing animation to make it stand out
	tween(boosterGraphics, {
		scaleX: 1.0,
		scaleY: 1.0
	}, {
		duration: 500,
		easing: tween.easeInOut,
		onFinish: function onFinish() {
			tween(boosterGraphics, {
				scaleX: 0.8,
				scaleY: 0.8
			}, {
				duration: 500,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					// Restart the pulsing animation
					if (!self.caught) {
						tween(boosterGraphics, {
							scaleX: 1.0,
							scaleY: 1.0
						}, {
							duration: 500,
							easing: tween.easeInOut
						});
					}
				}
			});
		}
	});
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
var Life = Container.expand(function () {
	var self = Container.call(this);
	var heartGraphics = self.attachAsset('heart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.0,
		scaleY: 1.0
	});
	// Add neon glow effect with retrowave pink
	heartGraphics.tint = 0xff0066;
	self.setActive = function (active) {
		if (active) {
			heartGraphics.alpha = 1.0;
			heartGraphics.tint = 0xff0066; // Bright neon pink
		} else {
			heartGraphics.alpha = 0.3;
			heartGraphics.tint = 0x440022; // Dim dark pink
		}
	};
	return self;
});
var MicrophoneIcon = Container.expand(function () {
	var self = Container.call(this);
	// Create microphone icon using a shape asset
	var micGraphics = self.attachAsset('micBar', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 2.0,
		scaleY: 1.5
	});
	// Style the microphone with synthwave neon colors
	micGraphics.tint = 0x00ffcc;
	micGraphics.alpha = 0.6;
	// Audio detection state
	self.isActive = false;
	self.lastVolume = 0;
	self.update = function () {
		if (gameMode === 'microphone') {
			var currentVolume = facekit.volume;
			// Update visual state based on audio levels
			if (currentVolume > 0.3) {
				// Active state - bright glow
				if (!self.isActive) {
					self.isActive = true;
					tween(micGraphics, {
						tint: 0x00ff66,
						alpha: 1.0,
						scaleX: 2.4,
						scaleY: 1.8
					}, {
						duration: 100,
						easing: tween.easeOut
					});
				}
				// Beat detection - extra bright flash
				if (detectBeat()) {
					tween(micGraphics, {
						tint: 0xffffff,
						scaleX: 3.0,
						scaleY: 2.2
					}, {
						duration: 150,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							tween(micGraphics, {
								tint: 0x00ff66,
								scaleX: 2.4,
								scaleY: 1.8
							}, {
								duration: 200,
								easing: tween.easeIn
							});
						}
					});
				}
			} else if (currentVolume > 0.1) {
				// Medium activity - moderate glow
				if (self.isActive) {
					tween(micGraphics, {
						tint: 0x00ffcc,
						alpha: 0.8,
						scaleX: 2.2,
						scaleY: 1.6
					}, {
						duration: 200,
						easing: tween.easeInOut
					});
				}
				self.isActive = false;
			} else {
				// Inactive state - dim glow with subtle pulsing
				if (self.isActive) {
					self.isActive = false;
					tween(micGraphics, {
						tint: 0x004466,
						alpha: 0.5,
						scaleX: 2.0,
						scaleY: 1.5
					}, {
						duration: 300,
						easing: tween.easeOut
					});
				}
				// Subtle pulsing to show mic is available
				var pulsePhase = LK.ticks * 0.02;
				micGraphics.alpha = 0.4 + 0.2 * Math.sin(pulsePhase);
			}
			self.lastVolume = currentVolume;
		}
	};
	return self;
});
var Ship = Container.expand(function (shipType) {
	var self = Container.call(this);
	// Use the provided shipType or default to classicShip
	var assetType = shipType || 'classicShip';
	var shipGraphics = self.attachAsset(assetType, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 3.0,
		scaleY: 3.0
	});
	// Add glow effect
	shipGraphics.filters = [];
	self.currentLane = 1; // 0 = left, 1 = center, 2 = right
	self.targetX = 1024; // center position
	self.update = function () {
		// Smooth movement to target lane
		var diff = self.targetX - self.x;
		if (Math.abs(diff) > 2) {
			self.x += diff * 0.15;
		} else {
			self.x = self.targetX;
		}
	};
	self.moveToLane = function (lane) {
		self.currentLane = lane;
		if (lane === 0) {
			self.targetX = 341; // left lane
		} else if (lane === 1) {
			self.targetX = 1024; // center lane
		} else if (lane === 2) {
			self.targetX = 1707; // right lane
		}
		// Add movement animation
		tween(shipGraphics, {
			scaleX: 3.6,
			scaleY: 2.4
		}, {
			duration: 100,
			onFinish: function onFinish() {
				tween(shipGraphics, {
					scaleX: 3.0,
					scaleY: 3.0
				}, {
					duration: 100
				});
			}
		});
	};
	return self;
});
var UnlockableShip = Container.expand(function (shipData) {
	var self = Container.call(this);
	// Use ship data to create the ship graphics
	var shipGraphics = self.attachAsset(shipData.assetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 2.0,
		scaleY: 2.0
	});
	// Apply the ship's unique color
	shipGraphics.tint = shipData.color;
	// Store ship properties
	self.shipData = shipData;
	self.extraLives = shipData.extraLives;
	// Add glow effect for unlocked ships
	self.addGlowEffect = function () {
		tween(shipGraphics, {
			alpha: 1.2
		}, {
			duration: 500,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(shipGraphics, {
					alpha: 0.8
				}, {
					duration: 500,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						self.addGlowEffect();
					}
				});
			}
		});
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x0a0a0a
});
/**** 
* Game Code
****/ 
// Create synthwave background with gradient effect
game.setBackgroundColor(0x270050);
// Create moving background grid
var backgroundGrid = game.addChild(new BackgroundGrid());
// Array of synthwave tracks for classic mode
var synthwaveTracks = ['synthwave1', 'synthwave2', 'synthwave3', 'lofitrack', 'retrowave'];
// Ship unlocking system
var unlockedShips = storage.unlockedShips || [];
var availableShipTypes = ['ship1', 'ship2', 'ship3', 'ship4', 'ship5'];
var shipColors = [0xff0066, 0x00ffcc, 0xffcc00, 0x66ff00, 0xcc00ff];
var shipNames = ['Neon Striker', 'Cyber Cruiser', 'Solar Surfer', 'Plasma Rider', 'Void Walker'];
// Generate random ship data
function generateRandomShip() {
	var randomIndex = Math.floor(Math.random() * availableShipTypes.length);
	var baseColor = shipColors[randomIndex];
	// Add some randomization to the color
	var colorVariation = Math.floor(Math.random() * 0x333333);
	var finalColor = baseColor + colorVariation & 0xffffff;
	return {
		id: 'ship_' + Date.now() + '_' + Math.floor(Math.random() * 1000),
		assetId: availableShipTypes[randomIndex],
		color: finalColor,
		name: shipNames[randomIndex] + ' MK-' + (Math.floor(Math.random() * 9) + 1),
		extraLives: 1,
		unlocked: true
	};
}
// Current selected ship
var currentShipData = null;
var currentTrackIndex = 0; // Index of currently playing track
var completedTracks = []; // Array to track which tracks have been completed
var musicStartTime = 0; // Time when current music track started
var trackDuration = 60000; // Approximate track duration in milliseconds (60 seconds)
// Game state
var gameMode = 'menu'; // 'menu', 'classic', 'microphone'
var ship;
var blocks = [];
var score = 0;
var combo = 0;
var bestCombo = 0;
var lives = 3;
var maxLives = 3;
var lifeDisplays = [];
var lastSpawnTime = 0;
var spawnInterval = 1000; // 1 second
var gameSpeed = 1.0; // Speed multiplier for the game
var baseBlockSpeed = 8; // Base speed for blocks
var currentMusicTrack = null; // Track current playing music
// Beat detection variables
var audioBuffer = [];
var beatThreshold = 0.4;
var lastBeatTime = 0;
var minBeatInterval = 200; // Minimum ms between beats
var volumeHistory = [];
var bufferSize = 10;
var beatSensitivity = 1.5;
// Lane positions - equal width lanes
var lanePositions = [341, 1024, 1707];
// UI Elements
var scoreTxt = new Text2('Score: 0', {
	size: 60,
	fill: 0x00FFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 50;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var comboTxt = new Text2('Combo: 0', {
	size: 50,
	fill: 0xFF00FF
});
comboTxt.anchor.set(0, 0);
comboTxt.x = 50;
comboTxt.y = 120;
LK.gui.topLeft.addChild(comboTxt);
// Create life display hearts in top right
for (var lifeIndex = 0; lifeIndex < maxLives; lifeIndex++) {
	var lifeHeart = new Life();
	lifeHeart.x = -80 - lifeIndex * 80; // Position from right edge
	lifeHeart.y = 60;
	lifeHeart.setActive(true);
	lifeDisplays.push(lifeHeart);
	LK.gui.topRight.addChild(lifeHeart);
}
// Create menu window frame with neon border
var menuFrameBorder = LK.getAsset('menuFrameBorder', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0.6
});
menuFrameBorder.x = 0;
menuFrameBorder.y = -100;
LK.gui.center.addChild(menuFrameBorder);
// Create semi-transparent background panel
var menuFrame = LK.getAsset('menuFrame', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0.8
});
menuFrame.x = 0;
menuFrame.y = -100;
LK.gui.center.addChild(menuFrame);
// Add pulsing animation to border
tween(menuFrameBorder, {
	alpha: 0.8
}, {
	duration: 1000,
	easing: tween.easeInOut,
	onFinish: function onFinish() {
		tween(menuFrameBorder, {
			alpha: 0.4
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				// Restart the pulsing animation
				tween(menuFrameBorder, {
					alpha: 0.8
				}, {
					duration: 1000,
					easing: tween.easeInOut
				});
			}
		});
	}
});
// Create mode selection buttons with neon glow outline
var classicButton = new Text2('1. CLASSIC MODE\nBuilt-in synthwave music', {
	size: 60,
	fill: 0x00FFFF,
	stroke: 0x00FFFF,
	strokeThickness: 3
});
classicButton.anchor.set(0.5, 0.5);
classicButton.x = 0;
classicButton.y = -200;
LK.gui.center.addChild(classicButton);
var micButton = new Text2('2. MICROPHONE MODE\nSync with your music', {
	size: 60,
	fill: 0xFF00FF,
	stroke: 0xFF00FF,
	strokeThickness: 3
});
micButton.anchor.set(0.5, 0.5);
micButton.x = 0;
micButton.y = -50;
LK.gui.center.addChild(micButton);
var instructionTxt = new Text2('TAP A BUTTON TO SELECT MODE', {
	size: 50,
	fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.y = 150;
LK.gui.center.addChild(instructionTxt);
// Ship unlock UI elements (initially hidden)
var unlockFrameBorder = LK.getAsset('unlockBorder', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0
});
unlockFrameBorder.x = 0;
unlockFrameBorder.y = 0;
LK.gui.center.addChild(unlockFrameBorder);
var unlockFrame = LK.getAsset('unlockFrame', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0
});
unlockFrame.x = 0;
unlockFrame.y = 0;
LK.gui.center.addChild(unlockFrame);
var unlockTitleTxt = new Text2('SHIP UNLOCKED!', {
	size: 60,
	fill: 0x00FFFF
});
unlockTitleTxt.anchor.set(0.5, 0.5);
unlockTitleTxt.x = 0;
unlockTitleTxt.y = -120;
unlockTitleTxt.alpha = 0;
LK.gui.center.addChild(unlockTitleTxt);
var unlockDescTxt = new Text2('', {
	size: 40,
	fill: 0xFFFFFF
});
unlockDescTxt.anchor.set(0.5, 0.5);
unlockDescTxt.x = 0;
unlockDescTxt.y = -60;
unlockDescTxt.alpha = 0;
LK.gui.center.addChild(unlockDescTxt);
var unlockShipDisplay = null;
var unlockContinueTxt = new Text2('TAP TO CONTINUE', {
	size: 50,
	fill: 0xFF00FF
});
unlockContinueTxt.anchor.set(0.5, 0.5);
unlockContinueTxt.x = 0;
unlockContinueTxt.y = 120;
unlockContinueTxt.alpha = 0;
LK.gui.center.addChild(unlockContinueTxt);
// Create microphone icon (initially hidden)
var microphoneIcon = new MicrophoneIcon();
microphoneIcon.x = -80;
microphoneIcon.y = 200;
microphoneIcon.visible = false;
LK.gui.topRight.addChild(microphoneIcon);
// Create camera disable button
var cameraButton = new Text2('CAM', {
	size: 40,
	fill: 0x00ffff,
	stroke: 0x00ffff,
	strokeThickness: 2
});
cameraButton.anchor.set(0.5, 0.5);
cameraButton.x = -80;
cameraButton.y = 300;
cameraButton.visible = false;
LK.gui.topRight.addChild(cameraButton);
// Camera state tracking
var cameraEnabled = true;
// Create lane dividers
var lane1 = game.addChild(LK.getAsset('lane1', {
	x: 682,
	y: 0
}));
var lane2 = game.addChild(LK.getAsset('lane2', {
	x: 1366,
	y: 0
}));
// Create ship
ship = game.addChild(new Ship());
ship.x = 1024;
ship.y = 2400;
function startGame(mode) {
	gameMode = mode;
	score = 0;
	combo = 0;
	bestCombo = 0;
	// Calculate lives based on current ship
	var baseLives = 3;
	var extraLives = currentShipData ? currentShipData.extraLives : 0;
	lives = baseLives + extraLives;
	maxLives = lives;
	blocks = [];
	lastSpawnTime = 0;
	gameSpeed = 1.0; // Reset game speed
	currentTrackIndex = 0; // Reset track progression
	completedTracks = []; // Reset completed tracks
	musicStartTime = 0; // Reset music timer
	// Reset and update life display for new max lives
	// Remove existing life displays
	for (var i = 0; i < lifeDisplays.length; i++) {
		lifeDisplays[i].destroy();
	}
	lifeDisplays = [];
	// Create new life displays based on current max lives
	for (var lifeIndex = 0; lifeIndex < maxLives; lifeIndex++) {
		var lifeHeart = new Life();
		lifeHeart.x = -80 - lifeIndex * 80;
		lifeHeart.y = 60;
		lifeHeart.setActive(true);
		lifeDisplays.push(lifeHeart);
		LK.gui.topRight.addChild(lifeHeart);
	}
	// Reset beat detection variables
	audioBuffer = [];
	volumeHistory = [];
	lastBeatTime = 0;
	// Hide menu elements
	classicButton.visible = false;
	micButton.visible = false;
	instructionTxt.visible = false;
	menuFrame.visible = false;
	menuFrameBorder.visible = false;
	// Destroy existing ship and create new one with appropriate asset
	if (ship) {
		ship.destroy();
	}
	// Create ship with mode-specific asset
	if (mode === 'classic') {
		ship = game.addChild(new Ship('classicShip'));
	} else {
		ship = game.addChild(new Ship('microphoneShip'));
	}
	ship.x = 1024;
	ship.y = 2400;
	// Start background music only in classic mode
	if (mode === 'classic') {
		// Shuffle the playlist for randomized track order
		for (var i = synthwaveTracks.length - 1; i > 0; i--) {
			var j = Math.floor(Math.random() * (i + 1));
			var temp = synthwaveTracks[i];
			synthwaveTracks[i] = synthwaveTracks[j];
			synthwaveTracks[j] = temp;
		}
		// Start with first track in shuffled sequence
		currentMusicTrack = synthwaveTracks[currentTrackIndex];
		LK.playMusic(currentMusicTrack);
		musicStartTime = Date.now(); // Track when music started using current time
		// Hide microphone icon and camera button in classic mode
		microphoneIcon.visible = false;
		cameraButton.visible = false;
	} else {
		// Stop background music in microphone mode to focus on external audio
		currentMusicTrack = null;
		LK.stopMusic();
		// Facekit plugin automatically handles microphone access when volume is accessed
		// No initialization needed - just use facekit.volume for beat detection
		// Show microphone icon and camera button in microphone mode
		microphoneIcon.visible = true;
		cameraButton.visible = true;
		// Reset camera state when starting microphone mode
		cameraEnabled = true;
		cameraButton.setText('CAM');
		cameraButton.fill = 0x00ffff;
		cameraButton.stroke = 0x00ffff;
	}
	updateUI();
}
function spawnBlock() {
	var block;
	var random = Math.random();
	// 10% chance to spawn a bomb block
	if (random < 0.10) {
		block = new BombBlock();
		// 15% chance to spawn a booster block  
	} else if (random < 0.25) {
		block = new BoosterBlock();
	} else {
		block = new Block();
	}
	var lane;
	if (gameMode === 'microphone') {
		// Create more musical patterns based on audio intensity
		var intensity = facekit.volume;
		if (intensity > 0.8) {
			// High intensity - spawn in multiple lanes or center
			lane = Math.random() > 0.5 ? 1 : Math.floor(Math.random() * 3);
		} else if (intensity > 0.5) {
			// Medium intensity - prefer outer lanes
			lane = Math.random() > 0.5 ? 0 : 2;
		} else {
			// Low intensity - single random lane
			lane = Math.floor(Math.random() * 3);
		}
	} else {
		// Classic mode - random lane
		lane = Math.floor(Math.random() * 3);
	}
	block.lane = lane;
	block.x = lanePositions[lane];
	block.y = -50;
	block.speed = baseBlockSpeed * gameSpeed; // Apply game speed multiplier
	blocks.push(block);
	game.addChild(block);
}
function updateUI() {
	scoreTxt.setText('Score: ' + score);
	comboTxt.setText('Combo: ' + combo + ' (Best: ' + bestCombo + ')');
}
function checkCollisions() {
	for (var i = blocks.length - 1; i >= 0; i--) {
		var block = blocks[i];
		// Check if block is in ship's catch zone
		if (!block.caught && block.y >= ship.y - 100 && block.y <= ship.y + 100) {
			if (block.lane === ship.currentLane) {
				// Block caught!
				block.caught = true;
				// Check if it's a bomb block
				if (block instanceof BombBlock) {
					// Bomb effects - lose 2 lives and reset combo
					lives -= 2;
					combo = 0;
					// Update life display for lost lives
					for (var lifeIdx = Math.max(0, lives); lifeIdx < Math.min(lives + 2, lifeDisplays.length); lifeIdx++) {
						lifeDisplays[lifeIdx].setActive(false);
						// Add dramatic life loss animation - capture lifeIdx in closure
						(function (capturedIdx) {
							tween(lifeDisplays[capturedIdx], {
								scaleX: 2.0,
								scaleY: 2.0
							}, {
								duration: 300,
								onFinish: function onFinish() {
									tween(lifeDisplays[capturedIdx], {
										scaleX: 1.0,
										scaleY: 1.0
									}, {
										duration: 300
									});
								}
							});
						})(lifeIdx);
					}
					// Dramatic visual feedback for bomb
					LK.effects.flashScreen(0xff0000, 800);
					LK.effects.flashObject(ship, 0xff0000, 800);
					// Play miss sound for bomb hit
					LK.getSound('miss').play();
					// Check for game over
					if (lives <= 0) {
						// Unlock a new ship before showing game over
						var newShip = unlockNewShip();
						currentShipData = newShip;
						// Delay game over to show ship unlock
						LK.setTimeout(function () {
							LK.showGameOver();
						}, 3000);
						return;
					}
					// Check if it's a booster block
				} else if (block instanceof BoosterBlock) {
					// Booster effects
					score += 25 + combo * 3; // More points for booster
					combo += 2; // Extra combo bonus
					// Increase game speed (cap at 2.5x)
					gameSpeed = Math.min(gameSpeed + 0.2, 2.5);
					// Apply speed to all existing blocks
					for (var j = 0; j < blocks.length; j++) {
						blocks[j].speed = baseBlockSpeed * gameSpeed;
					}
					// Restart music with faster tempo (only in classic mode)
					if (gameMode === 'classic' && currentMusicTrack) {
						LK.stopMusic();
						// Small delay before restarting music to avoid audio glitches
						LK.setTimeout(function () {
							LK.playMusic(currentMusicTrack);
						}, 50);
					}
					// Special visual feedback for booster
					LK.effects.flashScreen(0xFFD700, 300);
					LK.effects.flashObject(ship, 0xFFD700, 500);
					// Play layered synthwave sounds for booster
					LK.getSound('synthBass').play();
					LK.setTimeout(function () {
						LK.getSound('synthLead').play();
					}, 100);
				} else {
					// Regular block
					score += 10 + combo * 2;
					combo++;
				}
				if (combo > bestCombo) {
					bestCombo = combo;
				}
				// Visual feedback
				LK.effects.flashObject(block, 0xffffff, 200);
				tween(block, {
					scaleX: 1.5,
					scaleY: 1.5,
					alpha: 0
				}, {
					duration: 200
				});
				// Play musical sound that matches the current track
				var trackSounds = {
					'synthwave1': ['synthBass', 'synthLead', 'synthDrum', 'synthChord'],
					'synthwave2': ['synthLead', 'synthChord', 'synthBass', 'synthDrum'],
					'synthwave3': ['synthDrum', 'synthBass', 'synthLead', 'synthChord'],
					'lofitrack': ['synthBass', 'synthChord'],
					'retrowave': ['synthLead', 'synthDrum', 'synthChord']
				};
				var soundsForTrack = trackSounds[currentMusicTrack] || ['synthBass', 'synthLead', 'synthDrum', 'synthChord'];
				// Calculate beat position based on music timing to stay in rhythm
				var baseBPM = 120;
				var currentBPM = baseBPM * gameSpeed;
				var beatLength = 60000 / currentBPM; // Beat duration in ms
				var timeElapsed = Date.now() - musicStartTime;
				var beatPosition = Math.floor(timeElapsed / beatLength % soundsForTrack.length);
				var rhythmicSound = soundsForTrack[beatPosition];
				LK.getSound(rhythmicSound).play();
				updateUI();
				// Remove block
				block.destroy();
				blocks.splice(i, 1);
				continue;
			}
		}
		// Check if block missed (passed ship)
		if (!block.caught && block.y > ship.y + 150) {
			if (block.lane === ship.currentLane) {
				// Block missed - lose life and reset combo
				lives--;
				combo = 0;
				// Update life display
				if (lives >= 0 && lives < lifeDisplays.length) {
					var currentLifeIndex = lives; // Capture current lives value
					lifeDisplays[currentLifeIndex].setActive(false);
					// Add life loss animation
					tween(lifeDisplays[currentLifeIndex], {
						scaleX: 1.5,
						scaleY: 1.5
					}, {
						duration: 200,
						onFinish: function onFinish() {
							tween(lifeDisplays[currentLifeIndex], {
								scaleX: 1.0,
								scaleY: 1.0
							}, {
								duration: 200
							});
						}
					});
				}
				LK.effects.flashScreen(0xff0000, 300);
				LK.getSound('miss').play();
				// Check for game over
				if (lives <= 0) {
					LK.showGameOver();
					return;
				}
				updateUI();
			}
			block.caught = true; // Mark as processed
		}
		// Remove blocks that are off screen
		if (block.y > 2800) {
			block.destroy();
			blocks.splice(i, 1);
		}
	}
}
function showShipUnlock(newShipData) {
	// Show unlock frame with animation
	tween(unlockFrameBorder, {
		alpha: 0.8
	}, {
		duration: 300
	});
	tween(unlockFrame, {
		alpha: 0.9
	}, {
		duration: 300
	});
	tween(unlockTitleTxt, {
		alpha: 1
	}, {
		duration: 300
	});
	// Update description text
	unlockDescTxt.setText(newShipData.name + '\n+1 Extra Life');
	tween(unlockDescTxt, {
		alpha: 1
	}, {
		duration: 300
	});
	// Create and display the unlocked ship
	if (unlockShipDisplay) {
		unlockShipDisplay.destroy();
	}
	unlockShipDisplay = new UnlockableShip(newShipData);
	unlockShipDisplay.x = 0;
	unlockShipDisplay.y = 20;
	LK.gui.center.addChild(unlockShipDisplay);
	unlockShipDisplay.addGlowEffect();
	tween(unlockContinueTxt, {
		alpha: 1
	}, {
		duration: 300
	});
	// Add pulsing animation to continue text
	tween(unlockContinueTxt, {
		scaleX: 1.1,
		scaleY: 1.1
	}, {
		duration: 800,
		easing: tween.easeInOut,
		onFinish: function onFinish() {
			tween(unlockContinueTxt, {
				scaleX: 1.0,
				scaleY: 1.0
			}, {
				duration: 800,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(unlockContinueTxt, {
						scaleX: 1.1,
						scaleY: 1.1
					}, {
						duration: 800,
						easing: tween.easeInOut
					});
				}
			});
		}
	});
}
function hideShipUnlock() {
	tween(unlockFrameBorder, {
		alpha: 0
	}, {
		duration: 300
	});
	tween(unlockFrame, {
		alpha: 0
	}, {
		duration: 300
	});
	tween(unlockTitleTxt, {
		alpha: 0
	}, {
		duration: 300
	});
	tween(unlockDescTxt, {
		alpha: 0
	}, {
		duration: 300
	});
	tween(unlockContinueTxt, {
		alpha: 0
	}, {
		duration: 300
	});
	if (unlockShipDisplay) {
		tween(unlockShipDisplay, {
			alpha: 0
		}, {
			duration: 300,
			onFinish: function onFinish() {
				unlockShipDisplay.destroy();
				unlockShipDisplay = null;
			}
		});
	}
}
function unlockNewShip() {
	// Generate a new random ship
	var newShip = generateRandomShip();
	// Add to unlocked ships
	unlockedShips.push(newShip);
	// Keep only the 5 most recent ships
	if (unlockedShips.length > 5) {
		unlockedShips = unlockedShips.slice(-5);
	}
	// Save to storage
	storage.unlockedShips = unlockedShips;
	// Show unlock animation
	showShipUnlock(newShip);
	return newShip;
}
function progressToNextTrack() {
	if (gameMode !== 'classic') {
		return;
	}
	// Mark current track as completed
	if (completedTracks.indexOf(synthwaveTracks[currentTrackIndex]) === -1) {
		completedTracks.push(synthwaveTracks[currentTrackIndex]);
	}
	// Move to next track
	currentTrackIndex++;
	// Check if all tracks have been completed
	if (currentTrackIndex >= synthwaveTracks.length) {
		// Unlock a new ship before showing victory
		var newShip = unlockNewShip();
		currentShipData = newShip;
		// Delay victory screen to show ship unlock
		LK.setTimeout(function () {
			LK.showYouWin();
		}, 3000);
		return;
	}
	// Play next track
	currentMusicTrack = synthwaveTracks[currentTrackIndex];
	LK.playMusic(currentMusicTrack);
	musicStartTime = Date.now(); // Reset music timer using current time
}
function detectBeat() {
	var currentVolume = facekit.volume;
	var currentTime = Date.now();
	// Add current volume to history buffer
	volumeHistory.push(currentVolume);
	if (volumeHistory.length > bufferSize) {
		volumeHistory.shift();
	}
	// Calculate average volume from buffer
	var avgVolume = 0;
	for (var i = 0; i < volumeHistory.length; i++) {
		avgVolume += volumeHistory[i];
	}
	avgVolume = avgVolume / volumeHistory.length;
	// Detect beat: current volume significantly higher than average
	var volumeSpike = currentVolume > avgVolume * beatSensitivity;
	var timeSinceLastBeat = currentTime - lastBeatTime;
	var beatDetected = volumeSpike && currentVolume > beatThreshold && timeSinceLastBeat > minBeatInterval;
	if (beatDetected) {
		lastBeatTime = currentTime;
		// Add visual feedback for beat detection
		LK.effects.flashScreen(0x440088, 100);
		return true;
	}
	return false;
}
function shouldSpawnBlock() {
	if (gameMode === 'microphone') {
		// Spawn based on beat detection from microphone input
		return detectBeat();
	} else {
		// Classic mode - spawn every second
		return LK.ticks - lastSpawnTime >= spawnInterval / (1000 / 60);
	}
}
// Button event handlers
classicButton.down = function (x, y, obj) {
	if (gameMode === 'menu') {
		// Add button press animation
		tween(classicButton, {
			scaleX: 1.1,
			scaleY: 1.1
		}, {
			duration: 100,
			onFinish: function onFinish() {
				tween(classicButton, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100
				});
			}
		});
		startGame('classic');
	}
};
micButton.down = function (x, y, obj) {
	if (gameMode === 'menu') {
		// Add button press animation
		tween(micButton, {
			scaleX: 1.1,
			scaleY: 1.1
		}, {
			duration: 100,
			onFinish: function onFinish() {
				tween(micButton, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100
				});
			}
		});
		startGame('microphone');
	}
};
// Camera button event handler
cameraButton.down = function (x, y, obj) {
	if (gameMode === 'microphone') {
		// Toggle camera state
		cameraEnabled = !cameraEnabled;
		// Update button appearance based on state
		if (cameraEnabled) {
			cameraButton.setText('CAM');
			cameraButton.fill = 0x00ffff;
			cameraButton.stroke = 0x00ffff;
		} else {
			cameraButton.setText('CAM\nOFF');
			cameraButton.fill = 0xff0066;
			cameraButton.stroke = 0xff0066;
		}
		// Add button press animation
		tween(cameraButton, {
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 100,
			onFinish: function onFinish() {
				tween(cameraButton, {
					scaleX: 1.0,
					scaleY: 1.0
				}, {
					duration: 100
				});
			}
		});
		// Visual feedback
		LK.effects.flashObject(cameraButton, 0xffffff, 200);
	}
};
// Touch controls for lane switching during gameplay
game.down = function (x, y, obj) {
	if (gameMode === 'menu') {
		return;
	}
	// Check if unlock screen is visible
	if (unlockFrame.alpha > 0) {
		hideShipUnlock();
		return;
	}
	// Lane switching
	if (x < 1024) {
		// Left side tapped - move left
		if (ship.currentLane > 0) {
			ship.moveToLane(ship.currentLane - 1);
		}
	} else {
		// Right side tapped - move right
		if (ship.currentLane < 2) {
			ship.moveToLane(ship.currentLane + 1);
		}
	}
};
// Main game update
game.update = function () {
	if (gameMode === 'menu') {
		// Hide microphone icon and camera button in menu
		microphoneIcon.visible = false;
		cameraButton.visible = false;
		return;
	}
	// Check for track progression in classic mode
	if (gameMode === 'classic' && musicStartTime > 0) {
		var currentTime = Date.now();
		var timeElapsed = currentTime - musicStartTime;
		// Check if current track duration has been reached
		if (timeElapsed >= trackDuration) {
			progressToNextTrack();
		}
	}
	// Spawn blocks
	if (shouldSpawnBlock()) {
		spawnBlock();
		lastSpawnTime = LK.ticks;
	}
	// Check collisions
	checkCollisions();
};
:quality(85)/https://cdn.frvr.ai/685f01f1d2b74a34619be034.png%3F3) 
 synthwave neon glow audiosurf or f-zero like ship. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/685f46b5d2b74a34619be11e.png%3F3) 
 faint glowing outlines with a shimmer effect retro synthwave style. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/685f52d3c55577a60f471e19.png%3F3) 
 a musical note thats bright and neon thats also really cool looking. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/685f541bc55577a60f471e2a.png%3F3) 
 synthwave bright neon glow audiosurf or f-zero like ship In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/685f54a3c55577a60f471e39.png%3F3) 
 synthwave bright neon glow audiosurf or f-zero like ship In-Game asset. 2d. High contrast. No shadows. facing upright vertical
:quality(85)/https://cdn.frvr.ai/68603b4dd63214615d63fabc.png%3F3) 
 a musical note thats bright and neon thats also really cool looking. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/686044b2d63214615d63fc1a.png%3F3) 
 - Shape: a glowing neon **circle or hexagon** - Color: bright **red or magenta** - Inner symbol: a small white or yellow **skull**, **explosion**, or **⚠️ warning icon** in the center - Glow: apply a soft outer glow that pulses slightly - Visual style: match the **synthwave aesthetic** (think neon, arcade, retro-futuristic) - Size: same as the existing note blocks - Animation: gently pulsate or shimmer while falling. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68604994d63214615d63fcdb.png%3F3) 
 a bright laser vertical line retro style. In-Game asset. 2d. High contrast. No shadows. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6860603cd63214615d63ff6a.png%3F3) 
 a line that is set to the theme of this game that looks like lightsabre. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6860640ed63214615d63ffeb.png%3F3) 
 synthwave bright neon glow audiosurf or f-zero like ship In-Game asset. 2d. High contrast. No shadows. facing upright vertical 3d like