User prompt
pause ekranında bpm ve şarkı ismini gizle
User prompt
restart yapınca ready menüsüne atsın canlar yeniden yenilensin ve gerisayım bitene kadar oyun başlamasın, beatler spawn olmasın.
User prompt
restart yapınca sıfırdan yeni bir oyun başlasın arkada beatler devam etmesin
User prompt
pause menü butonlarını restart, resume assetleriyle güncelle
User prompt
pause menüsünden paused yazısını ve blurred assetini kaldır
User prompt
pause menü arkaplanını pausemenu asseti ile değiştir
User prompt
durdurduktan sonra pause button scale büyüyor büyümesin
User prompt
pause button scale 1.6 olsun
Code edit (1 edits merged)
Please save this source code
User prompt
pause button konumunu heartYden bağımsız yap ve 200px aşağı indir
Code edit (1 edits merged)
Please save this source code
User prompt
kalplere göre konumlandırma pause assetini
Code edit (1 edits merged)
Please save this source code
User prompt
pause button 150px aşağı indir
User prompt
buton kalbin 10px aşağısında olsun
User prompt
oyuna bir pause butonu ekle. resume, restart, main menu butonları olsun.
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	bpm: 100,
	soundVolume: 100,
	selectedKickSound: "kick",
	selectedHihatSound: "hihat",
	selectedSnareClapSound: "snareclap",
	selectedPercussionSound: "percussion"
});
/**** 
* Classes
****/ 
// default bpm 100
// Beat marker class (moving dot)
var BeatMarker = Container.expand(function () {
	var self = Container.call(this);
	var marker = self.attachAsset('beatMarker', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.active = true; // Whether this beat is still hittable
	self.hit = false; // Whether this beat was hit
	// For feedback animation
	self.showFeedback = function (type) {
		var feedbackId = type === 'good' ? 'goodCircle' : 'missCircle';
		var feedback = LK.getAsset(feedbackId, {
			anchorX: 0.5,
			anchorY: 0.5,
			x: self.x,
			y: self.y,
			alpha: 0.7,
			scaleX: 1,
			scaleY: 1
		});
		game.addChild(feedback);
		tween(feedback, {
			alpha: 0,
			scaleX: 1.5,
			scaleY: 1.5
		}, {
			duration: 400,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				feedback.destroy();
			}
		});
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x6ec6f5 // light blue sky
});
/**** 
* Game Code
****/ 
// --- Game constants ---
// Bass drum (kick) hit circle
// Bass drum (kick) hit circle when active
// Timeline bar
// Beat marker
// Miss feedback
// Good feedback
// Sound for kick
// Music (looping, short demo)
// --- BPM-specific music assets (kickless versions) ---
var TIMELINE_WIDTH = 2048;
var TIMELINE_HEIGHT = 25;
var TIMELINE_Y = 2000; // Y position of timeline bar
var TIMELINE_X = 0;
var HIT_ZONE_X = 2048 / 2; // Center of screen
var HIT_ZONE_Y = TIMELINE_Y + TIMELINE_HEIGHT / 2;
var HIT_WINDOW = 120; // px distance for perfect hit
// Beat speed remains constant - only spacing between beats changes based on BPM
function getBeatSpeed() {
	return 400; // Constant speed of 400 px/s regardless of BPM
}
var INITIAL_BPM = 100; // Starting BPM
var BEATS_PER_MEASURE = 4;
var BEAT_INTERVAL = 60 / INITIAL_BPM; // seconds per beat
var DIFFICULTY_STEP = 0.15; // How much to increase BPM per level
var MAX_MISSES = 5;
// --- Game state ---
var beats = []; // Active BeatMarker objects
var beatPattern = []; // Array of {time, type}
var nextBeatIdx = 0; // Next beat to spawn
var songTime = 0; // Elapsed time in seconds
var lastTickTime = Date.now();
var score = 0;
var misses = 0;
var ignoredMisses = 0; // Track first 3 misses to ignore
var combo = 0;
var bpm = typeof storage.bpm === "number" ? storage.bpm : INITIAL_BPM;
var soundVolume = typeof storage.soundVolume === "number" ? storage.soundVolume : 100;
var selectedKickSound = typeof storage.selectedKickSound === "string" ? storage.selectedKickSound : 'kick';
var selectedHihatSound = typeof storage.selectedHihatSound === "string" ? storage.selectedHihatSound : 'hihat';
var selectedSnareClapSound = typeof storage.selectedSnareClapSound === "string" ? storage.selectedSnareClapSound : 'snareclap';
var selectedPercussionSound = typeof storage.selectedPercussionSound === "string" ? storage.selectedPercussionSound : 'percussion';
// Function to update all sound volumes based on soundVolume setting
function updateAllSoundVolumes() {
	var volumeMultiplier = soundVolume / 100;
	// Update kick sound volume
	var kickSound = LK.getSound(selectedKickSound);
	if (kickSound && kickSound.setVolume) {
		kickSound.setVolume(1 * volumeMultiplier);
	}
	// Update hihat sound volume
	var hihatSound = LK.getSound(selectedHihatSound);
	if (hihatSound && hihatSound.setVolume) {
		hihatSound.setVolume(0.5 * volumeMultiplier);
	}
	// Update snare/clap sound volume
	var snareClapSound = LK.getSound(selectedSnareClapSound);
	if (snareClapSound && snareClapSound.setVolume) {
		snareClapSound.setVolume(0.6 * volumeMultiplier);
	}
	// Update percussion sound volume
	var percussionSound = LK.getSound(selectedPercussionSound);
	if (percussionSound && percussionSound.setVolume) {
		percussionSound.setVolume(0.6 * volumeMultiplier);
	}
	// Update miss sound volume
	var missSound = LK.getSound('miss');
	if (missSound && missSound.setVolume) {
		missSound.setVolume(0.6 * volumeMultiplier);
	}
}
var beatInterval = 60 / bpm;
var gameActive = true;
var feedbackTimeout = null;
// --- UI elements ---
// --- Heart/Life UI ---
// (Initialization moved after scoreTxt is defined)
var MAX_LIVES = 3;
var lives = MAX_LIVES;
var heartIcons = [];
var heartSpacing = 40;
var heartshields = 3; // Number of heartshields remaining
// Heart/life UI will be initialized after scoreTxt is defined
// --- Gameplay Screen Container ---
var gamescreen = new Container();
gamescreen.visible = false;
game.addChild(gamescreen);
// Add isyeri background image, anchored top-left, covering the whole game area
var isyeriBg = LK.getAsset('isyeri', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 2732
});
gamescreen.addChild(isyeriBg);
var timelineBar = LK.getAsset('timelineBar', {
	anchorX: 0,
	anchorY: 0.5,
	x: TIMELINE_X,
	y: TIMELINE_Y + TIMELINE_HEIGHT / 2
});
gamescreen.addChild(timelineBar);
// Hit zone (kick target)
var kickTarget = LK.getAsset('kickTarget', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: HIT_ZONE_X,
	y: HIT_ZONE_Y
});
gamescreen.addChild(kickTarget);
// Score text - pixelated effect using small size and scale
var scoreTxt = new Text2('0', {
	size: 20,
	fill: 0xFFFFFF
});
scoreTxt.scale.set(6, 6); // Scale up 6x to create more pixelated effect
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Combo text
var comboTxt = new Text2('', {
	size: 12,
	fill: 0x00FF00
});
comboTxt.scale.set(6, 6);
comboTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(comboTxt);
comboTxt.y = 120;
// BPM display text - 180px below combo text (moved 20px up)
var bpmDisplayTxt = new Text2(bpm + ' ' + 'BPM', {
	size: 12,
	fill: 0xef69b9
});
bpmDisplayTxt.scale.set(6, 6);
bpmDisplayTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(bpmDisplayTxt);
bpmDisplayTxt.y = comboTxt.y + 180;
// Song name display text - below BPM display
var songNameTxt = new Text2('', {
	size: 12,
	fill: 0xffffff
});
songNameTxt.scale.set(6, 6);
songNameTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(songNameTxt);
songNameTxt.y = bpmDisplayTxt.y + 75;
// Pause button in top right corner (avoiding top-left platform menu)
var pauseBtn = LK.getAsset('pause', {
	anchorX: 1,
	anchorY: 0,
	x: 2048 - 50,
	y: 220,
	scaleX: 1.6,
	scaleY: 1.6
});
gamescreen.addChild(pauseBtn);
// No miss text, only hearts for lives display
// --- Heart/Life UI --- (moved here to ensure scoreTxt is defined)
// Calculate heartY based on scoreTxt position and height
var heartY = scoreTxt.y + 50; // Score text'in 50px altında
var heartWidth = 150;
var totalHeartsWidth = MAX_LIVES * heartWidth + (MAX_LIVES - 1) * heartSpacing;
var heartStartX = 2048 - 100 - totalHeartsWidth; // Sağdan 100px boşluk bırak
// Remove any existing heart icons from their parents before recreating
for (var i = 0; i < heartIcons.length; i++) {
	if (heartIcons[i] && heartIcons[i].parent) {
		heartIcons[i].parent.removeChild(heartIcons[i]);
	}
}
heartIcons = [];
for (var i = 0; i < MAX_LIVES; i++) {
	var heartshield = LK.getAsset('heartshield', {
		anchorX: 0,
		anchorY: 0,
		x: heartStartX + i * (heartWidth + heartSpacing),
		y: heartY
	});
	gamescreen.addChild(heartshield);
	heartIcons.push(heartshield);
}
// --- Beat pattern generation ---
function generateBeatPattern(bpm, measures) {
	// Simple: 4/4, kick on every beat, can add more complex patterns later
	var pattern = [];
	var interval = 60 / bpm; // seconds per beat based on current BPM
	var totalBeats = 100000; // Target 100,000 total beats
	for (var beatIndex = 0; beatIndex < totalBeats; beatIndex++) {
		pattern.push({
			time: beatIndex * interval,
			// Each beat spaced by BPM interval
			type: 'kick'
		});
	}
	return pattern;
}
// --- Start game ---
function startGame() {
	// Reset state
	for (var i = 0; i < beats.length; i++) {
		beats[i].destroy();
	}
	beats = [];
	// Always use current bpm from settings and calculate beatInterval accordingly
	beatInterval = 60 / bpm;
	beatPattern = generateBeatPattern(bpm); // Generate 100,000 beats
	nextBeatIdx = 0;
	songTime = 0;
	lastTickTime = Date.now();
	score = 0;
	misses = 0;
	ignoredMisses = 0; // Reset ignored misses counter
	combo = 0;
	perfectCombo = 0; // Reset perfect combo
	lives = MAX_LIVES;
	heartshields = 3; // Reset heartshields
	lastBpmUpgradeScore = 0; // Reset BPM upgrade tracking
	// Remove any beat that is at the kick target at game start (defensive, in case of bug)
	// Also, prevent initial miss by ensuring no beat is at or past the hit zone at game start
	for (var i = beats.length - 1; i >= 0; i--) {
		if (typeof beats[i].x !== "undefined" && Math.abs(beats[i].x - HIT_ZONE_X) < 2 || typeof beats[i].x !== "undefined" && beats[i].x >= HIT_ZONE_X - HIT_WINDOW) {
			beats[i].destroy();
			beats.splice(i, 1);
		}
	}
	// Defensive: Also ensure no beat is created at the kick target at game start
	if (beats.length > 0 && typeof beats[0].x !== "undefined" && Math.abs(beats[0].x - HIT_ZONE_X) < 2) {
		beats[0].destroy();
		beats.splice(0, 1);
	}
	// Reset heart icons to full heartshields
	// Recalculate miss text width and heart positions on restart
	var heartWidth = 150;
	var totalHeartsWidth = MAX_LIVES * heartWidth + (MAX_LIVES - 1) * heartSpacing;
	var heartStartX = 2048 - 100 - totalHeartsWidth;
	var heartY = scoreTxt.y + 50;
	// Remove all existing heart icons
	for (var i = 0; i < heartIcons.length; i++) {
		if (heartIcons[i] && heartIcons[i].parent) {
			heartIcons[i].parent.removeChild(heartIcons[i]);
		}
	}
	// Recreate all heart icons as full heartshields
	heartIcons = [];
	heartshields = MAX_LIVES; // Reset heartshields counter first
	lives = MAX_LIVES; // Reset lives counter to ensure proper state
	for (var i = 0; i < MAX_LIVES; i++) {
		var heartAsset = LK.getAsset('heartshield', {
			anchorX: 0,
			anchorY: 0,
			x: heartStartX + i * (heartWidth + heartSpacing),
			y: heartY
		});
		gamescreen.addChild(heartAsset);
		heartIcons.push(heartAsset);
	}
	gameActive = true;
	gamePaused = false;
	scoreTxt.setText('0');
	comboTxt.setText('');
	// missTxt removed, only hearts for lives
	kickTarget.visible = true;
	LK.setScore(0);
	// Reapply glow effects after game restart
	applyGlowToVioletElements();
	// Apply current sound volume settings
	updateAllSoundVolumes();
	// Set timeout to remove heartshields after 3 seconds
	tween({}, {}, {
		duration: 3000,
		onFinish: function onFinish() {
			if (gameActive && heartshields > 0) {
				// Convert all remaining heartshields to regular hearts
				for (var i = 0; i < MAX_LIVES; i++) {
					if (heartIcons[i] && heartIcons[i].parent) {
						// Check if this is still a heartshield by checking if heartshields counter allows it
						var shieldIndex = 3 - heartshields;
						if (i >= shieldIndex) {
							// This is a heartshield, convert it to heart
							var parent = heartIcons[i].parent;
							parent.removeChild(heartIcons[i]);
							heartIcons[i] = LK.getAsset('heart', {
								anchorX: 0,
								anchorY: 0,
								x: heartStartX + i * (heartWidth + heartSpacing),
								y: heartY
							});
							gamescreen.addChild(heartIcons[i]);
						}
					}
				}
				// Reset heartshields counter to 0
				heartshields = 0;
			}
		}
	});
	// --- Play correct BPM music (kickless) ---
	var musicId = '100BPMSynthWave'; // Default fallback
	if (bpm === 40) {
		musicId = '40BPMDeepVibes';
	} else if (bpm === 45) {
		musicId = '45BPMChillWave';
	} else if (bpm === 50) {
		musicId = '50BPMSlowMotion';
	} else if (bpm === 55) {
		musicId = '55BPMDreamscape';
	} else if (bpm === 60) {
		musicId = '60BPMLowKey';
	} else if (bpm === 65) {
		musicId = '65BPMRelaxed';
	} else if (bpm === 70) {
		musicId = '70BPMCalmVibes';
	} else if (bpm === 75) {
		musicId = '75BPMElectricDreams';
	} else if (bpm === 80) {
		musicId = '80BPMNeonNights';
	} else if (bpm === 85) {
		musicId = '85BPMCyberFlow';
	} else if (bpm === 90) {
		musicId = '90BPMDigitalPulse';
	} else if (bpm === 95) {
		musicId = '95BPMFutureBass';
	} else if (bpm === 100) {
		musicId = '100BPMSynthWave';
	} else if (bpm === 105) {
		musicId = '105BPMHyperDrive';
	} else if (bpm === 110) {
		musicId = '110BPMTechnoRush';
	} else if (bpm === 115) {
		musicId = '115BPMHighEnergy';
	} else if (bpm === 120) {
		musicId = '120BPMMaximum';
	}
	var volumeMultiplier = soundVolume / 100;
	LK.playMusic(musicId, {
		volume: 1 * volumeMultiplier,
		loop: true
	});
	// Update song name display
	if (songNameTxt) {
		// Remove BPM number and "BPM" text from the beginning
		var songName = musicId.replace(/^\d+BPM/, '');
		songNameTxt.setText(songName);
	}
}
// --- Main Menu Implementation ---
// Add main menu background image, anchored top-left, covering the whole game area
var mainMenuContainer = new Container();
mainMenuContainer.visible = true;
var mainMenuBg = LK.getAsset('mainmanubg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 2732
});
mainMenuContainer.addChild(mainMenuBg);
// Title - DJ Asset
var djAsset = LK.getAsset('DJ', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 315,
	scaleX: 8,
	scaleY: 8
});
mainMenuContainer.addChild(djAsset);
// Calculate button positions with 5px spacing
var buttonStartY = 1000;
var buttonHeight = 289; // Approximate height with scale 5
var buttonSpacing = 5;
// Start Button
var startBtn = LK.getAsset('startbutton', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: buttonStartY,
	scaleX: 5,
	scaleY: 5
});
mainMenuContainer.addChild(startBtn);
// Settings Button
var settingsBtn = LK.getAsset('settingsbutton', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: buttonStartY + buttonHeight + buttonSpacing,
	scaleX: 5,
	scaleY: 5
});
mainMenuContainer.addChild(settingsBtn);
// Credits Button
var creditsBtn = LK.getAsset('creditsbutton', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: buttonStartY + 2 * (buttonHeight + buttonSpacing),
	scaleX: 5,
	scaleY: 5
});
mainMenuContainer.addChild(creditsBtn);
// Support Us Button
var supportBtn = LK.getAsset('supportbutton', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: buttonStartY + 3 * (buttonHeight + buttonSpacing),
	scaleX: 5,
	scaleY: 5
});
mainMenuContainer.addChild(supportBtn);
// Overlay for credits/settings/support
var settingsmenu = new Container();
settingsmenu.visible = false;
game.addChild(settingsmenu);
var creditsmenu = new Container();
creditsmenu.visible = false;
game.addChild(creditsmenu);
var supportmenu = new Container();
supportmenu.visible = false;
game.addChild(supportmenu);
// Helper to hide all overlays
function hideAllMenus() {
	settingsmenu.visible = false;
	creditsmenu.visible = false;
	supportmenu.visible = false;
}
// Show credits menu
function showCreditsMenu() {
	hideAllMenus();
	creditsmenu.removeChildren();
	var bg = LK.getAsset('creditsbg', {
		anchorX: 0,
		anchorY: 0,
		x: 0,
		y: 0,
		width: 2048,
		height: 2732
	});
	creditsmenu.addChild(bg);
	var creditsTab = LK.getAsset('creditstab', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 2732 / 2,
		scaleX: 10,
		scaleY: 10
	});
	creditsmenu.addChild(creditsTab);
	// Close button (bottom right)
	var closeBtn = LK.getAsset('closebutton', {
		anchorX: 1,
		anchorY: 1,
		x: 2048 - 60,
		y: 2732 - 60,
		scaleX: 3,
		scaleY: 3
	});
	creditsmenu.addChild(closeBtn);
	closeBtn.down = function (x, y, obj) {
		// Play button click sound
		LK.getSound('buttonclick').play();
		// Click animation - scale inward then outward
		tween(closeBtn, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 80,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				tween(closeBtn, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 120,
					easing: tween.easeOut
				});
			}
		});
		creditsmenu.visible = false;
		mainMenuContainer.visible = true;
	};
	creditsmenu.visible = true;
	// Remove tap-to-close on background
	creditsmenu.down = undefined;
}
// Show support menu
function showSupportMenu() {
	hideAllMenus();
	supportmenu.removeChildren();
	var bg = LK.getAsset('supportbg', {
		anchorX: 0,
		anchorY: 0,
		x: 0,
		y: 0,
		width: 2048,
		height: 2732
	});
	supportmenu.addChild(bg);
	var supportTab = LK.getAsset('supporttab', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 2732 / 2,
		scaleX: 10,
		scaleY: 10
	});
	supportmenu.addChild(supportTab);
	// Close button (bottom right)
	var closeBtn = LK.getAsset('closebutton', {
		anchorX: 1,
		anchorY: 1,
		x: 2048 - 60,
		y: 2732 - 60,
		scaleX: 3,
		scaleY: 3
	});
	supportmenu.addChild(closeBtn);
	closeBtn.down = function (x, y, obj) {
		// Play button click sound
		LK.getSound('buttonclick').play();
		// Click animation - scale inward then outward
		tween(closeBtn, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 80,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				tween(closeBtn, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 120,
					easing: tween.easeOut
				});
			}
		});
		supportmenu.visible = false;
		mainMenuContainer.visible = true;
	};
	supportmenu.visible = true;
	// Remove tap-to-close on background
	supportmenu.down = undefined;
	// Play thanks sound after 2 seconds
	LK.setTimeout(function () {
		LK.getSound('thanks').play();
	}, 2000);
}
// Show settings menu
function showSettingsMenu() {
	hideAllMenus();
	settingsmenu.removeChildren();
	var bg = LK.getAsset('settingsbg', {
		anchorX: 0,
		anchorY: 0,
		x: 0,
		y: 0,
		width: 2048,
		height: 2732
	});
	settingsmenu.addChild(bg);
	var settingsAsset = LK.getAsset('settingsbutton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 700,
		scaleX: 8,
		scaleY: 8
	});
	settingsmenu.addChild(settingsAsset);
	// --- BPM CIRCLE UI ---
	// Container for the whole BPM control
	var bpmCircleContainer = new Container();
	bpmCircleContainer.x = 2048 / 2 - 300;
	bpmCircleContainer.y = 1100;
	settingsmenu.addChild(bpmCircleContainer);
	// --- KICK SOUND SELECTION UI ---
	// Container for kick sound selection
	var kickSoundContainer = new Container();
	kickSoundContainer.x = 2048 / 2;
	kickSoundContainer.y = 1400;
	settingsmenu.addChild(kickSoundContainer);
	// Kick sound label
	var kickSoundLabelTxt = new Text2("KICK SOUND", {
		size: 12,
		fill: 0xffffff
	});
	kickSoundLabelTxt.scale.set(4, 4);
	kickSoundLabelTxt.anchor.set(0.5, 0.5);
	kickSoundLabelTxt.x = 0;
	kickSoundLabelTxt.y = -120;
	kickSoundContainer.addChild(kickSoundLabelTxt);
	// Add settingsbar background behind kick buttons
	var kickSettingsBar = LK.getAsset('settingsbar', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		scaleX: 1.2,
		scaleY: 1.2,
		alpha: 0.8
	});
	kickSoundContainer.addChild(kickSettingsBar);
	// Create kick sound buttons
	var kickSounds = ['kick', 'kick2', 'kick3', 'kick4'];
	var kickButtons = [];
	var buttonSpacing = 220;
	var startX = -330;
	for (var i = 0; i < kickSounds.length; i++) {
		var kickButton = LK.getAsset('purplecircle', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: startX + i * buttonSpacing,
			y: 0,
			scaleX: 0.8,
			scaleY: 0.8,
			alpha: selectedKickSound === kickSounds[i] ? 1 : 0.5
		});
		kickSoundContainer.addChild(kickButton);
		// Add number text to button
		var numberTxt = new Text2(i + 1 + "", {
			size: 18,
			fill: 0xffffff
		});
		numberTxt.scale.set(4, 4);
		numberTxt.anchor.set(0.5, 0.5);
		numberTxt.x = startX + i * buttonSpacing;
		numberTxt.y = 0;
		kickSoundContainer.addChild(numberTxt);
		kickButton.kickSoundId = kickSounds[i];
		kickButton.buttonIndex = i;
		kickButtons.push(kickButton);
		// Button click handler
		kickButton.down = function (x, y, obj) {
			// If this is already selected kick sound and any other sound is selected, deselect all kick sounds
			if (selectedKickSound === this.kickSoundId && (selectedHihatSound !== '' || selectedSnareClapSound !== '' || selectedPercussionSound !== '')) {
				// Play the selected kick sound
				LK.getSound(this.kickSoundId).play();
				// Deselect all kick sounds
				selectedKickSound = '';
				storage.selectedKickSound = selectedKickSound;
				// Update button appearances - all kick buttons become inactive
				for (var j = 0; j < kickButtons.length; j++) {
					kickButtons[j].alpha = 0.5;
				}
				// Animate button
				tween(this, {
					scaleX: 0.9,
					scaleY: 0.9
				}, {
					duration: 80,
					easing: tween.easeIn,
					onFinish: function () {
						tween(this, {
							scaleX: 0.8,
							scaleY: 0.8
						}, {
							duration: 120,
							easing: tween.easeOut
						});
					}.bind(this)
				});
				return;
			}
			// If this is already selected and it's the only one selected, don't allow deselection
			if (selectedKickSound === this.kickSoundId && selectedHihatSound === '' && selectedSnareClapSound === '' && selectedPercussionSound === '') {
				// Play the selected kick sound
				LK.getSound(this.kickSoundId).play();
				return; // Don't deselect if it would leave no sound selected
			}
			// Play the selected kick sound
			LK.getSound(this.kickSoundId).play();
			// Update selected kick sound
			selectedKickSound = this.kickSoundId;
			storage.selectedKickSound = selectedKickSound;
			// Update button appearances
			for (var j = 0; j < kickButtons.length; j++) {
				kickButtons[j].alpha = j === this.buttonIndex ? 1 : 0.5;
			}
			// Animate button
			tween(this, {
				scaleX: 0.9,
				scaleY: 0.9
			}, {
				duration: 80,
				easing: tween.easeIn,
				onFinish: function () {
					tween(this, {
						scaleX: 0.8,
						scaleY: 0.8
					}, {
						duration: 120,
						easing: tween.easeOut
					});
				}.bind(this)
			});
		}.bind(kickButton);
	}
	// --- HIHAT SOUND SELECTION UI ---
	// Container for hihat sound selection
	var hihatSoundContainer = new Container();
	hihatSoundContainer.x = 2048 / 2;
	hihatSoundContainer.y = 1700;
	settingsmenu.addChild(hihatSoundContainer);
	// Hihat sound label
	var hihatSoundLabelTxt = new Text2("HI HATS", {
		size: 12,
		fill: 0xffffff
	});
	hihatSoundLabelTxt.scale.set(4, 4);
	hihatSoundLabelTxt.anchor.set(0.5, 0.5);
	hihatSoundLabelTxt.x = 0;
	hihatSoundLabelTxt.y = -120;
	hihatSoundContainer.addChild(hihatSoundLabelTxt);
	// Add settingsbar background behind hihat buttons
	var hihatSettingsBar = LK.getAsset('settingsbar', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		scaleX: 1.2,
		scaleY: 1.2,
		alpha: 0.8
	});
	hihatSoundContainer.addChild(hihatSettingsBar);
	// Create hihat sound buttons
	var hihatSounds = ['hihat', 'hihat2', 'hihat3', 'hihat4'];
	var hihatButtons = [];
	var hihatButtonSpacing = 220;
	var hihatStartX = -330;
	for (var i = 0; i < hihatSounds.length; i++) {
		var hihatButton = LK.getAsset('purplecircle', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: hihatStartX + i * hihatButtonSpacing,
			y: 0,
			scaleX: 0.8,
			scaleY: 0.8,
			alpha: selectedHihatSound === hihatSounds[i] ? 1 : 0.5
		});
		hihatSoundContainer.addChild(hihatButton);
		// Add number text to button
		var numberTxt = new Text2(i + 1 + "", {
			size: 18,
			fill: 0xffffff
		});
		numberTxt.scale.set(4, 4);
		numberTxt.anchor.set(0.5, 0.5);
		numberTxt.x = hihatStartX + i * hihatButtonSpacing;
		numberTxt.y = 0;
		hihatSoundContainer.addChild(numberTxt);
		hihatButton.hihatSoundId = hihatSounds[i];
		hihatButton.buttonIndex = i;
		hihatButtons.push(hihatButton);
		// Button click handler
		hihatButton.down = function (x, y, obj) {
			// If this is already selected hihat sound and any other sound is selected, deselect all hihat sounds
			if (selectedHihatSound === this.hihatSoundId && (selectedKickSound !== '' || selectedSnareClapSound !== '' || selectedPercussionSound !== '')) {
				// Play the selected hihat sound
				LK.getSound(this.hihatSoundId).play();
				// Deselect all hihat sounds
				selectedHihatSound = '';
				storage.selectedHihatSound = selectedHihatSound;
				// Update button appearances - all hihat buttons become inactive
				for (var j = 0; j < hihatButtons.length; j++) {
					hihatButtons[j].alpha = 0.5;
				}
				// Animate button
				tween(this, {
					scaleX: 0.9,
					scaleY: 0.9
				}, {
					duration: 80,
					easing: tween.easeIn,
					onFinish: function () {
						tween(this, {
							scaleX: 0.8,
							scaleY: 0.8
						}, {
							duration: 120,
							easing: tween.easeOut
						});
					}.bind(this)
				});
				return;
			}
			// If this is already selected and it's the only one selected, don't allow deselection
			if (selectedHihatSound === this.hihatSoundId && selectedKickSound === '' && selectedSnareClapSound === '' && selectedPercussionSound === '') {
				// Play the selected hihat sound
				LK.getSound(this.hihatSoundId).play();
				return; // Don't deselect if it would leave no sound selected
			}
			// Play the selected hihat sound
			LK.getSound(this.hihatSoundId).play();
			// Update selected hihat sound
			selectedHihatSound = this.hihatSoundId;
			storage.selectedHihatSound = selectedHihatSound;
			// Update button appearances
			for (var j = 0; j < hihatButtons.length; j++) {
				hihatButtons[j].alpha = j === this.buttonIndex ? 1 : 0.5;
			}
			// Animate button
			tween(this, {
				scaleX: 0.9,
				scaleY: 0.9
			}, {
				duration: 80,
				easing: tween.easeIn,
				onFinish: function () {
					tween(this, {
						scaleX: 0.8,
						scaleY: 0.8
					}, {
						duration: 120,
						easing: tween.easeOut
					});
				}.bind(this)
			});
		}.bind(hihatButton);
	}
	// --- SNARE/CLAP SOUND SELECTION UI ---
	// Container for snare/clap sound selection
	var snareClapSoundContainer = new Container();
	snareClapSoundContainer.x = 2048 / 2;
	snareClapSoundContainer.y = 2000;
	settingsmenu.addChild(snareClapSoundContainer);
	// Snare/clap sound label
	var snareClapSoundLabelTxt = new Text2("SNARE/CLAP", {
		size: 12,
		fill: 0xffffff
	});
	snareClapSoundLabelTxt.scale.set(4, 4);
	snareClapSoundLabelTxt.anchor.set(0.5, 0.5);
	snareClapSoundLabelTxt.x = 0;
	snareClapSoundLabelTxt.y = -120;
	snareClapSoundContainer.addChild(snareClapSoundLabelTxt);
	// Add settingsbar background behind snare/clap buttons
	var snareClapSettingsBar = LK.getAsset('settingsbar', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		scaleX: 1.2,
		scaleY: 1.2,
		alpha: 0.8
	});
	snareClapSoundContainer.addChild(snareClapSettingsBar);
	// Create snare/clap sound buttons
	var snareClapSounds = ['snareclap', 'snareclap2', 'snareclap3', 'snareclap4'];
	var snareClapButtons = [];
	var snareClapButtonSpacing = 220;
	var snareClapStartX = -330;
	for (var i = 0; i < snareClapSounds.length; i++) {
		var snareClapButton = LK.getAsset('purplecircle', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: snareClapStartX + i * snareClapButtonSpacing,
			y: 0,
			scaleX: 0.8,
			scaleY: 0.8,
			alpha: selectedSnareClapSound === snareClapSounds[i] ? 1 : 0.5
		});
		snareClapSoundContainer.addChild(snareClapButton);
		// Add number text to button
		var numberTxt = new Text2(i + 1 + "", {
			size: 18,
			fill: 0xffffff
		});
		numberTxt.scale.set(4, 4);
		numberTxt.anchor.set(0.5, 0.5);
		numberTxt.x = snareClapStartX + i * snareClapButtonSpacing;
		numberTxt.y = 0;
		snareClapSoundContainer.addChild(numberTxt);
		snareClapButton.snareClapSoundId = snareClapSounds[i];
		snareClapButton.buttonIndex = i;
		snareClapButtons.push(snareClapButton);
		// Button click handler
		snareClapButton.down = function (x, y, obj) {
			// If this is already selected snare/clap sound and any other sound is selected, deselect all snare/clap sounds
			if (selectedSnareClapSound === this.snareClapSoundId && (selectedKickSound !== '' || selectedHihatSound !== '' || selectedPercussionSound !== '')) {
				// Play the selected snare/clap sound
				LK.getSound(this.snareClapSoundId).play();
				// Deselect all snare/clap sounds
				selectedSnareClapSound = '';
				storage.selectedSnareClapSound = selectedSnareClapSound;
				// Update button appearances - all snare/clap buttons become inactive
				for (var j = 0; j < snareClapButtons.length; j++) {
					snareClapButtons[j].alpha = 0.5;
				}
				// Animate button
				tween(this, {
					scaleX: 0.9,
					scaleY: 0.9
				}, {
					duration: 80,
					easing: tween.easeIn,
					onFinish: function () {
						tween(this, {
							scaleX: 0.8,
							scaleY: 0.8
						}, {
							duration: 120,
							easing: tween.easeOut
						});
					}.bind(this)
				});
				return;
			}
			// If this is already selected and it's the only one selected, don't allow deselection
			if (selectedSnareClapSound === this.snareClapSoundId && selectedKickSound === '' && selectedHihatSound === '' && selectedPercussionSound === '') {
				// Play the selected snare/clap sound
				LK.getSound(this.snareClapSoundId).play();
				return; // Don't deselect if it would leave no sound selected
			}
			// Play the selected snare/clap sound
			LK.getSound(this.snareClapSoundId).play();
			// Update selected snare/clap sound
			selectedSnareClapSound = this.snareClapSoundId;
			storage.selectedSnareClapSound = selectedSnareClapSound;
			// Update button appearances
			for (var j = 0; j < snareClapButtons.length; j++) {
				snareClapButtons[j].alpha = j === this.buttonIndex ? 1 : 0.5;
			}
			// Animate button
			tween(this, {
				scaleX: 0.9,
				scaleY: 0.9
			}, {
				duration: 80,
				easing: tween.easeIn,
				onFinish: function () {
					tween(this, {
						scaleX: 0.8,
						scaleY: 0.8
					}, {
						duration: 120,
						easing: tween.easeOut
					});
				}.bind(this)
			});
		}.bind(snareClapButton);
	}
	// --- PERCUSSION SOUND SELECTION UI ---
	// Container for percussion sound selection
	var percussionSoundContainer = new Container();
	percussionSoundContainer.x = 2048 / 2;
	percussionSoundContainer.y = 2300;
	settingsmenu.addChild(percussionSoundContainer);
	// Percussion sound label
	var percussionSoundLabelTxt = new Text2("PERCUSSION", {
		size: 12,
		fill: 0xffffff
	});
	percussionSoundLabelTxt.scale.set(4, 4);
	percussionSoundLabelTxt.anchor.set(0.5, 0.5);
	percussionSoundLabelTxt.x = 0;
	percussionSoundLabelTxt.y = -120;
	percussionSoundContainer.addChild(percussionSoundLabelTxt);
	// Add settingsbar background behind percussion buttons
	var percussionSettingsBar = LK.getAsset('settingsbar', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		scaleX: 1.2,
		scaleY: 1.2,
		alpha: 0.8
	});
	percussionSoundContainer.addChild(percussionSettingsBar);
	// Create percussion sound buttons
	var percussionSounds = ['percussion', 'percussion2', 'percussion3', 'percussion4'];
	var percussionButtons = [];
	var percussionButtonSpacing = 220;
	var percussionStartX = -330;
	for (var i = 0; i < percussionSounds.length; i++) {
		var percussionButton = LK.getAsset('purplecircle', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: percussionStartX + i * percussionButtonSpacing,
			y: 0,
			scaleX: 0.8,
			scaleY: 0.8,
			alpha: selectedPercussionSound === percussionSounds[i] ? 1 : 0.5
		});
		percussionSoundContainer.addChild(percussionButton);
		// Add number text to button
		var numberTxt = new Text2(i + 1 + "", {
			size: 18,
			fill: 0xffffff
		});
		numberTxt.scale.set(4, 4);
		numberTxt.anchor.set(0.5, 0.5);
		numberTxt.x = percussionStartX + i * percussionButtonSpacing;
		numberTxt.y = 0;
		percussionSoundContainer.addChild(numberTxt);
		percussionButton.percussionSoundId = percussionSounds[i];
		percussionButton.buttonIndex = i;
		percussionButtons.push(percussionButton);
		// Button click handler
		percussionButton.down = function (x, y, obj) {
			// If this is already selected percussion sound and any other sound is selected, deselect all percussion sounds
			if (selectedPercussionSound === this.percussionSoundId && (selectedKickSound !== '' || selectedHihatSound !== '' || selectedSnareClapSound !== '')) {
				// Play the selected percussion sound
				LK.getSound(this.percussionSoundId).play();
				// Deselect all percussion sounds
				selectedPercussionSound = '';
				storage.selectedPercussionSound = selectedPercussionSound;
				// Update button appearances - all percussion buttons become inactive
				for (var j = 0; j < percussionButtons.length; j++) {
					percussionButtons[j].alpha = 0.5;
				}
				// Animate button
				tween(this, {
					scaleX: 0.9,
					scaleY: 0.9
				}, {
					duration: 80,
					easing: tween.easeIn,
					onFinish: function () {
						tween(this, {
							scaleX: 0.8,
							scaleY: 0.8
						}, {
							duration: 120,
							easing: tween.easeOut
						});
					}.bind(this)
				});
				return;
			}
			// If this is already selected and it's the only one selected, don't allow deselection
			if (selectedPercussionSound === this.percussionSoundId && selectedKickSound === '' && selectedHihatSound === '' && selectedSnareClapSound === '') {
				// Play the selected percussion sound
				LK.getSound(this.percussionSoundId).play();
				return; // Don't deselect if it would leave no sound selected
			}
			// Play the selected percussion sound
			LK.getSound(this.percussionSoundId).play();
			// Update selected percussion sound
			selectedPercussionSound = this.percussionSoundId;
			storage.selectedPercussionSound = selectedPercussionSound;
			// Update button appearances
			for (var j = 0; j < percussionButtons.length; j++) {
				percussionButtons[j].alpha = j === this.buttonIndex ? 1 : 0.5;
			}
			// Animate button
			tween(this, {
				scaleX: 0.9,
				scaleY: 0.9
			}, {
				duration: 80,
				easing: tween.easeIn,
				onFinish: function () {
					tween(this, {
						scaleX: 0.8,
						scaleY: 0.8
					}, {
						duration: 120,
						easing: tween.easeOut
					});
				}.bind(this)
			});
		}.bind(percussionButton);
	}
	// --- SOUND VOLUME CIRCLE UI ---
	// Container for the whole sound volume control
	var volumeCircleContainer = new Container();
	volumeCircleContainer.x = 2048 / 2 + 300;
	volumeCircleContainer.y = 1100;
	settingsmenu.addChild(volumeCircleContainer);
	// Circle background
	var bpmCircleBg = LK.getAsset('purplecircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		scaleX: 1.1,
		scaleY: 1.1,
		alpha: 0.85
	});
	bpmCircleContainer.addChild(bpmCircleBg);
	// BPM value text
	var bpmValueTxt = new Text2(bpm + "", {
		size: 18,
		fill: 0xffffff
	});
	bpmValueTxt.scale.set(6, 6);
	bpmValueTxt.anchor.set(0.5, 0.5);
	bpmValueTxt.x = 0;
	bpmValueTxt.y = 0;
	bpmCircleContainer.addChild(bpmValueTxt);
	// BPM label text
	var bpmLabelTxt = new Text2("BPM", {
		size: 8,
		fill: 0xffffff
	});
	bpmLabelTxt.scale.set(6, 6);
	bpmLabelTxt.anchor.set(0.5, 0.5);
	bpmLabelTxt.x = 0;
	bpmLabelTxt.y = 90;
	bpmCircleContainer.addChild(bpmLabelTxt);
	// Volume circle background
	var volumeCircleBg = LK.getAsset('purplecircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		scaleX: 1.1,
		scaleY: 1.1,
		alpha: 0.85
	});
	volumeCircleContainer.addChild(volumeCircleBg);
	// Volume value text
	var volumeValueTxt = new Text2((typeof storage.soundVolume === "number" ? storage.soundVolume : 100) + "", {
		size: 18,
		fill: 0xffffff
	});
	volumeValueTxt.scale.set(6, 6);
	volumeValueTxt.anchor.set(0.5, 0.5);
	volumeValueTxt.x = 0;
	volumeValueTxt.y = 0;
	volumeCircleContainer.addChild(volumeValueTxt);
	// Volume label text
	var volumeLabelTxt = new Text2("SOUND", {
		size: 8,
		fill: 0xffffff
	});
	volumeLabelTxt.scale.set(6, 6);
	volumeLabelTxt.anchor.set(0.5, 0.5);
	volumeLabelTxt.x = 0;
	volumeLabelTxt.y = 90;
	volumeCircleContainer.addChild(volumeLabelTxt);
	// --- Drag-to-change BPM logic ---
	var dragActive = false;
	var dragStartY = 0;
	var dragStartBpm = 0;
	var lastDragStep = 0;
	var BPM_MIN = 40;
	var BPM_MAX = 120;
	var BPM_STEP = 5;
	var PIXELS_PER_STEP = 20;
	// Touch start (down) on circle
	bpmCircleContainer.down = function (x, y, obj) {
		dragActive = true;
		dragStartY = y;
		dragStartBpm = bpm;
		lastDragStep = 0;
		// Animate circle slightly for feedback
		tween(bpmCircleBg, {
			scaleX: 1.18,
			scaleY: 1.18
		}, {
			duration: 100,
			yoyo: true,
			repeat: 1
		});
	};
	// Touch move on circle
	bpmCircleContainer.move = function (x, y, obj) {
		if (!dragActive) {
			return;
		}
		var dy = dragStartY - y; // Up is positive
		var step = Math.floor(dy / PIXELS_PER_STEP);
		if (step !== lastDragStep) {
			var newBpm = dragStartBpm + step * BPM_STEP;
			if (newBpm < BPM_MIN) {
				newBpm = BPM_MIN;
			}
			if (newBpm > BPM_MAX) {
				newBpm = BPM_MAX;
			}
			if (newBpm !== bpm) {
				bpm = newBpm;
				bpmValueTxt.setText(bpm + "");
				beatInterval = 60 / bpm; // Recalculate beat interval for new BPM
				// Regenerate beat pattern with new BPM intervals
				beatPattern = generateBeatPattern(bpm);
				nextBeatIdx = 0; // Reset beat spawning
				storage.bpm = bpm; // persist bpm to storage
				// Play scratch sound when BPM changes during settings
				LK.getSound('scratch').play();
				if (bpmDisplayTxt) {
					bpmDisplayTxt.setText(bpm + ' BPM');
				}
			}
			lastDragStep = step;
		}
	};
	// Touch end (up) on circle
	bpmCircleContainer.up = function (x, y, obj) {
		dragActive = false;
		// Animate back to normal scale
		tween(bpmCircleBg, {
			scaleX: 1.1,
			scaleY: 1.1
		}, {
			duration: 100
		});
	};
	// --- Volume drag logic ---
	var volumeDragActive = false;
	var volumeDragStartY = 0;
	var volumeDragStartValue = 0;
	var volumeLastDragStep = 0;
	var VOLUME_MIN = 0;
	var VOLUME_MAX = 100;
	var VOLUME_STEP = 5;
	var VOLUME_PIXELS_PER_STEP = 20;
	// Touch start (down) on volume circle
	volumeCircleContainer.down = function (x, y, obj) {
		volumeDragActive = true;
		volumeDragStartY = y;
		volumeDragStartValue = soundVolume;
		volumeLastDragStep = 0;
		// Animate circle slightly for feedback
		tween(volumeCircleBg, {
			scaleX: 1.18,
			scaleY: 1.18
		}, {
			duration: 100,
			yoyo: true,
			repeat: 1
		});
	};
	// Touch move on volume circle
	volumeCircleContainer.move = function (x, y, obj) {
		if (!volumeDragActive) {
			return;
		}
		var dy = volumeDragStartY - y; // Up is positive
		var step = Math.floor(dy / VOLUME_PIXELS_PER_STEP);
		if (step !== volumeLastDragStep) {
			var newVolume = volumeDragStartValue + step * VOLUME_STEP;
			if (newVolume < VOLUME_MIN) {
				newVolume = VOLUME_MIN;
			}
			if (newVolume > VOLUME_MAX) {
				newVolume = VOLUME_MAX;
			}
			if (newVolume !== soundVolume) {
				soundVolume = newVolume;
				volumeValueTxt.setText(soundVolume + "");
				storage.soundVolume = soundVolume; // persist volume to storage
				updateAllSoundVolumes(); // Update all sound volumes immediately
				// Update current playing music volume immediately
				var currentVolumeMultiplier = soundVolume / 100;
				LK.playMusic('menumusic', {
					volume: 0.8 * currentVolumeMultiplier,
					loop: true
				});
			}
			volumeLastDragStep = step;
		}
	};
	// Touch end (up) on volume circle
	volumeCircleContainer.up = function (x, y, obj) {
		volumeDragActive = false;
		// Animate back to normal scale
		tween(volumeCircleBg, {
			scaleX: 1.1,
			scaleY: 1.1
		}, {
			duration: 100
		});
	};
	// Close button (bottom right)
	var closeBtn = LK.getAsset('closebutton', {
		anchorX: 1,
		anchorY: 1,
		x: 2048 - 60,
		y: 2732 - 60,
		scaleX: 3,
		scaleY: 3
	});
	settingsmenu.addChild(closeBtn);
	closeBtn.down = function (x, y, obj) {
		// Play button click sound
		LK.getSound('buttonclick').play();
		// Click animation - scale inward then outward
		tween(closeBtn, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 80,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				tween(closeBtn, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 120,
					easing: tween.easeOut
				});
			}
		});
		settingsmenu.visible = false;
		mainMenuContainer.visible = true;
	};
	// Remove tap-to-close on background
	settingsmenu.down = undefined;
	settingsmenu.visible = true;
}
// Button event handlers
// Countdown logic
var countdownContainer = new Container();
countdownContainer.visible = false;
game.addChild(countdownContainer);
// Pre-game ready screen container
var readyContainer = new Container();
readyContainer.visible = false;
game.addChild(readyContainer);
function showReadyScreen(onReady) {
	gamescreen.visible = true;
	readyContainer.visible = true;
	readyContainer.removeChildren();
	// Show arrowtap area
	var arrowTap = LK.getAsset('arrowtap', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: HIT_ZONE_X - 150,
		y: HIT_ZONE_Y + 250,
		scaleX: 3,
		scaleY: 3
	});
	readyContainer.addChild(arrowTap);
	// Show ready button
	var readyBtn = LK.getAsset('readybutton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 2732 / 2 + 350,
		scaleX: 6,
		scaleY: 6
	});
	readyContainer.addChild(readyBtn);
	// Add readyinfo asset on top of readybutton
	var readyInfo = LK.getAsset('readyinfo', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 2732 / 2 - 375,
		scaleX: 1.1,
		scaleY: 1.1
	});
	readyContainer.addChild(readyInfo);
	// Ready button click handler
	readyBtn.down = function (x, y, obj) {
		// Play button click sound
		LK.getSound('buttonclick').play();
		// Click animation
		tween(readyBtn, {
			scaleX: 7.2,
			scaleY: 7.2
		}, {
			duration: 80,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				tween(readyBtn, {
					scaleX: 8,
					scaleY: 8
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						readyContainer.visible = false;
						readyContainer.removeChildren();
						if (typeof onReady === "function") {
							onReady();
						}
					}
				});
			}
		});
	};
}
function showCountdown(onFinish) {
	gamescreen.visible = true;
	countdownContainer.visible = true;
	countdownContainer.removeChildren();
	var numbers = ["3", "2", "1"];
	var idx = 0;
	function showNext() {
		if (idx >= numbers.length) {
			countdownContainer.visible = false;
			countdownContainer.removeChildren();
			// Only show gamescreen if game is active (startGame will set it visible)
			if (!gameActive) {
				gamescreen.visible = false;
			}
			if (typeof onFinish === "function") {
				onFinish();
			}
			return;
		}
		countdownContainer.removeChildren();
		var txt = new Text2(numbers[idx], {
			size: 600,
			fill: 0xffd700
		});
		txt.scale.set(160, 160);
		txt.anchor.set(0.5, 0.5);
		txt.x = 2048 / 2;
		txt.y = 1200;
		txt.alpha = 0;
		txt.scale.x = 0.6;
		txt.scale.y = 0.6;
		countdownContainer.addChild(txt);
		// Animate in
		tween(txt, {
			alpha: 1,
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 250,
			easing: tween.cubicOut,
			onFinish: function onFinish() {
				// Hold, then animate out
				tween(txt, {
					alpha: 0,
					scaleX: 1.5,
					scaleY: 1.5
				}, {
					duration: 350,
					delay: 400,
					easing: tween.cubicIn,
					onFinish: function onFinish() {
						idx++;
						showNext();
					}
				});
			}
		});
	}
	idx = 0;
	showNext();
}
startBtn.down = function (x, y, obj) {
	// Play button click sound
	LK.getSound('buttonclick').play();
	// Stop menu music immediately and fade out over 1 second
	LK.stopMusic();
	var volumeMultiplier = soundVolume / 100;
	LK.playMusic('menumusic', {
		volume: 0.8 * volumeMultiplier,
		fade: {
			start: 1,
			end: 0,
			duration: 1000
		}
	});
	// Click animation - scale inward then outward
	tween(startBtn, {
		scaleX: 4.5,
		scaleY: 4.5
	}, {
		duration: 80,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			tween(startBtn, {
				scaleX: 5,
				scaleY: 5
			}, {
				duration: 120,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					mainMenuContainer.visible = false;
					showReadyScreen(function () {
						showCountdown(function () {
							startGame();
						});
					});
				}
			});
		}
	});
};
settingsBtn.down = function (x, y, obj) {
	// Play button click sound
	LK.getSound('buttonclick').play();
	// Click animation - scale inward then outward
	tween(settingsBtn, {
		scaleX: 4.5,
		scaleY: 4.5
	}, {
		duration: 80,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			tween(settingsBtn, {
				scaleX: 5,
				scaleY: 5
			}, {
				duration: 120,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					mainMenuContainer.visible = false;
					showSettingsMenu();
				}
			});
		}
	});
};
creditsBtn.down = function (x, y, obj) {
	// Play button click sound
	LK.getSound('buttonclick').play();
	// Click animation - scale inward then outward
	tween(creditsBtn, {
		scaleX: 4.5,
		scaleY: 4.5
	}, {
		duration: 80,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			tween(creditsBtn, {
				scaleX: 5,
				scaleY: 5
			}, {
				duration: 120,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					mainMenuContainer.visible = false;
					showCreditsMenu();
				}
			});
		}
	});
};
supportBtn.down = function (x, y, obj) {
	// Play button click sound
	LK.getSound('buttonclick').play();
	// Click animation - scale inward then outward
	tween(supportBtn, {
		scaleX: 4.5,
		scaleY: 4.5
	}, {
		duration: 80,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			tween(supportBtn, {
				scaleX: 5,
				scaleY: 5
			}, {
				duration: 120,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					mainMenuContainer.visible = false;
					showSupportMenu();
				}
			});
		}
	});
};
// Music mute button in bottom corner of main menu
var musicMuted = typeof storage.musicMuted === "boolean" ? storage.musicMuted : false;
var musicMuteBtn = LK.getAsset('purplecircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 - 150,
	y: 2732 - 150,
	scaleX: 0.8,
	scaleY: 0.8,
	alpha: musicMuted ? 0.5 : 1
});
mainMenuContainer.addChild(musicMuteBtn);
// Music icon text on button
var musicIconTxt = new Text2(musicMuted ? "M" : "♪", {
	size: 24,
	fill: 0xffffff
});
musicIconTxt.scale.set(4, 4);
musicIconTxt.anchor.set(0.5, 0.5);
musicIconTxt.x = 2048 - 150;
musicIconTxt.y = 2732 - 150;
mainMenuContainer.addChild(musicIconTxt);
// Music mute button handler
musicMuteBtn.down = function (x, y, obj) {
	// Play button click sound
	LK.getSound('buttonclick').play();
	// Toggle mute state
	musicMuted = !musicMuted;
	storage.musicMuted = musicMuted;
	// Update button appearance
	musicMuteBtn.alpha = musicMuted ? 0.5 : 1;
	musicIconTxt.setText(musicMuted ? "M" : "♪");
	// Handle music playback
	if (musicMuted) {
		LK.stopMusic();
	} else {
		var volumeMultiplier = soundVolume / 100;
		LK.playMusic('menumusic', {
			volume: 0.8 * volumeMultiplier,
			loop: true
		});
	}
	// Click animation
	tween(musicMuteBtn, {
		scaleX: 0.72,
		scaleY: 0.72
	}, {
		duration: 80,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			tween(musicMuteBtn, {
				scaleX: 0.8,
				scaleY: 0.8
			}, {
				duration: 120,
				easing: tween.easeOut
			});
		}
	});
};
// Add menu to game
game.addChild(mainMenuContainer);
// menus are already added above
// Hide all gameplay UI until game starts
scoreTxt.visible = false;
comboTxt.visible = false;
bpmDisplayTxt.visible = false;
songNameTxt.visible = false;
// missTxt removed, only hearts for lives
// timelineBar and kickTarget are now children of gamescreen, so their visibility is managed by gamescreen
// Patch startGame to show gameplay UI and gamescreen
var _originalStartGame = startGame;
startGame = function startGame() {
	scoreTxt.visible = true;
	comboTxt.visible = true;
	bpmDisplayTxt.visible = true;
	songNameTxt.visible = true;
	if (bpmDisplayTxt) {
		bpmDisplayTxt.setText(bpm + ' BPM');
	}
	// missTxt removed, only hearts for lives
	gamescreen.visible = true;
	mainMenuContainer.visible = false;
	// overlayContainer.visible = false; // Removed, not defined
	_originalStartGame();
};
// On menu, hide gameplay UI and gamescreen
mainMenuContainer.visible = true;
scoreTxt.visible = false;
comboTxt.visible = false;
bpmDisplayTxt.visible = false;
songNameTxt.visible = false;
gamescreen.visible = false;
// Play menu music when in main menu (only if not muted)
if (!musicMuted) {
	var volumeMultiplier = soundVolume / 100;
	LK.playMusic('menumusic', {
		volume: 0.8 * volumeMultiplier,
		loop: true
	});
}
// Apply current sound volume settings to all sounds
updateAllSoundVolumes();
// Pause button functionality
pauseBtn.down = function (x, y, obj) {
	if (!gameActive || !gamescreen.visible) {
		return;
	}
	// Play button click sound
	LK.getSound('buttonclick').play();
	// Pause the game
	gamePaused = true;
	showPauseMenu();
	// No animation - button scale remains fixed at 1.6
};
// Show pause menu function
function showPauseMenu() {
	pauseContainer.visible = true;
	pauseContainer.removeChildren();
	// Hide BPM and song name in pause menu
	bpmDisplayTxt.visible = false;
	songNameTxt.visible = false;
	// Pause menu background
	var pauseMenuBg = LK.getAsset('pausemenu', {
		anchorX: 0,
		anchorY: 0,
		x: 0,
		y: 0,
		width: 2048,
		height: 2732
	});
	pauseContainer.addChild(pauseMenuBg);
	// Button positions
	var pauseButtonStartY = 1200;
	var pauseButtonHeight = 289;
	var pauseButtonSpacing = 20;
	// Resume button
	var resumeBtn = LK.getAsset('resumebutton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: pauseButtonStartY,
		scaleX: 5,
		scaleY: 5
	});
	pauseContainer.addChild(resumeBtn);
	// Restart button
	var restartBtn = LK.getAsset('restartbutton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: pauseButtonStartY + pauseButtonHeight + pauseButtonSpacing,
		scaleX: 5,
		scaleY: 5
	});
	pauseContainer.addChild(restartBtn);
	// Main menu button
	var pauseMainMenuBtn = LK.getAsset('mainmenu', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: pauseButtonStartY + 2 * (pauseButtonHeight + pauseButtonSpacing),
		scaleX: 5,
		scaleY: 5
	});
	pauseContainer.addChild(pauseMainMenuBtn);
	// Resume button handler
	resumeBtn.down = function (x, y, obj) {
		LK.getSound('buttonclick').play();
		tween(resumeBtn, {
			scaleX: 4.5,
			scaleY: 4.5
		}, {
			duration: 80,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				tween(resumeBtn, {
					scaleX: 5,
					scaleY: 5
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						resumeGame();
					}
				});
			}
		});
	};
	// Restart button handler
	restartBtn.down = function (x, y, obj) {
		LK.getSound('buttonclick').play();
		tween(restartBtn, {
			scaleX: 4.5,
			scaleY: 4.5
		}, {
			duration: 80,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				tween(restartBtn, {
					scaleX: 5,
					scaleY: 5
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						pauseContainer.visible = false;
						gamePaused = false;
						gameActive = false; // Stop game temporarily during restart
						maxCombo = 0;
						perfectCount = 0;
						maxPerfectCombo = 0;
						// Reset lives and hearts before showing ready screen
						lives = MAX_LIVES;
						heartshields = 3; // Reset heartshields
						// Remove all existing heart icons
						for (var i = 0; i < heartIcons.length; i++) {
							if (heartIcons[i] && heartIcons[i].parent) {
								heartIcons[i].parent.removeChild(heartIcons[i]);
							}
						}
						// Recreate all heart icons as full heartshields
						heartIcons = [];
						var heartY = scoreTxt.y + 50;
						var heartWidth = 150;
						var totalHeartsWidth = MAX_LIVES * heartWidth + (MAX_LIVES - 1) * heartSpacing;
						var heartStartX = 2048 - 100 - totalHeartsWidth;
						for (var i = 0; i < MAX_LIVES; i++) {
							var heartAsset = LK.getAsset('heartshield', {
								anchorX: 0,
								anchorY: 0,
								x: heartStartX + i * (heartWidth + heartSpacing),
								y: heartY
							});
							gamescreen.addChild(heartAsset);
							heartIcons.push(heartAsset);
						}
						showReadyScreen(function () {
							showCountdown(function () {
								startGame();
							});
						});
					}
				});
			}
		});
	};
	// Pause main menu button handler
	pauseMainMenuBtn.down = function (x, y, obj) {
		LK.getSound('buttonclick').play();
		tween(pauseMainMenuBtn, {
			scaleX: 4.5,
			scaleY: 4.5
		}, {
			duration: 80,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				tween(pauseMainMenuBtn, {
					scaleX: 5,
					scaleY: 5
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						pauseContainer.visible = false;
						gamePaused = false;
						gameActive = false;
						maxCombo = 0;
						perfectCount = 0;
						maxPerfectCombo = 0;
						mainMenuContainer.visible = true;
						scoreTxt.visible = false;
						comboTxt.visible = false;
						bpmDisplayTxt.visible = false;
						songNameTxt.visible = false;
						gamescreen.visible = false;
						// Stop current music and play menu music (only if not muted)
						LK.stopMusic();
						if (!musicMuted) {
							LK.setTimeout(function () {
								var volumeMultiplier = soundVolume / 100;
								LK.playMusic('menumusic', {
									volume: 0.8 * volumeMultiplier,
									loop: true
								});
							}, 100);
						}
					}
				});
			}
		});
	};
}
// Resume game function
function resumeGame() {
	gamePaused = false;
	pauseContainer.visible = false;
	// Show BPM and song name when resuming
	bpmDisplayTxt.visible = true;
	songNameTxt.visible = true;
	lastTickTime = Date.now(); // Reset time to prevent time jump
}
// --- Beat spawning ---
function spawnBeat(beat) {
	var marker = new BeatMarker();
	// All beats spawn at left edge of screen (x=0)
	marker.x = 0; // Always spawn at left edge
	marker.y = HIT_ZONE_Y;
	marker.beatTime = beat.time;
	marker.type = beat.type;
	marker.active = true;
	marker.hit = false;
	marker.lastX = marker.x; // initialize lastX for correct miss logic
	marker.hasReachedHitZone = false; // initialize for correct miss logic
	beats.push(marker);
	gamescreen.addChild(marker);
}
// --- Game update ---
game.update = function () {
	if (!gameActive || gamePaused) {
		return;
	}
	// Time management
	var now = Date.now();
	var dt = (now - lastTickTime) / 1000;
	lastTickTime = now;
	songTime += dt;
	// Prevent beat spawning until countdown is finished and gameplay is visible
	if (!gamescreen.visible || countdownContainer.visible) {
		return;
	}
	// Only allow beat spawning after countdown is finished
	if (!countdownContainer.visible) {
		// Spawn new beats with constant speed and BPM-based timing
		var currentBeatSpeed = getBeatSpeed(); // Always 400 px/s
		// Calculate travel time from left edge (x=0) to hit zone
		var travelTime = HIT_ZONE_X / currentBeatSpeed; // Time needed to travel from x=0 to hit zone
		// Spawn beats at the right time so they arrive at hit zone exactly when needed
		while (nextBeatIdx < beatPattern.length && beatPattern[nextBeatIdx].time - songTime <= travelTime) {
			spawnBeat(beatPattern[nextBeatIdx]);
			nextBeatIdx++;
		}
	}
	// Check for BPM progression every 10,000 points
	if (score >= 10000 && score - lastBpmUpgradeScore >= 10000) {
		if (bpm < 120) {
			// Don't increase BPM beyond 120
			lastBpmUpgradeScore = score;
			var oldBpm = bpm;
			bpm = Math.min(120, bpm + 5); // Increase by 5 BPM, cap at 120
			if (bpm !== oldBpm) {
				// Update BPM display
				if (bpmDisplayTxt) {
					bpmDisplayTxt.setText(bpm + ' BPM');
				}
				// Update beat interval for new beats
				beatInterval = 60 / bpm;
				// Get new music ID
				var newMusicId = '100BPMSynthWave'; // Default fallback
				if (bpm === 40) {
					newMusicId = '40BPMDeepVibes';
				} else if (bpm === 45) {
					newMusicId = '45BPMChillWave';
				} else if (bpm === 50) {
					newMusicId = '50BPMSlowMotion';
				} else if (bpm === 55) {
					newMusicId = '55BPMDreamscape';
				} else if (bpm === 60) {
					newMusicId = '60BPMLowKey';
				} else if (bpm === 65) {
					newMusicId = '65BPMRelaxed';
				} else if (bpm === 70) {
					newMusicId = '70BPMCalmVibes';
				} else if (bpm === 75) {
					newMusicId = '75BPMElectricDreams';
				} else if (bpm === 80) {
					newMusicId = '80BPMNeonNights';
				} else if (bpm === 85) {
					newMusicId = '85BPMCyberFlow';
				} else if (bpm === 90) {
					newMusicId = '90BPMDigitalPulse';
				} else if (bpm === 95) {
					newMusicId = '95BPMFutureBass';
				} else if (bpm === 100) {
					newMusicId = '100BPMSynthWave';
				} else if (bpm === 105) {
					newMusicId = '105BPMHyperDrive';
				} else if (bpm === 110) {
					newMusicId = '110BPMTechnoRush';
				} else if (bpm === 115) {
					newMusicId = '115BPMHighEnergy';
				} else if (bpm === 120) {
					newMusicId = '120BPMMaximum';
				}
				// Fade out current music and fade in new music
				var volumeMultiplier = soundVolume / 100;
				LK.stopMusic();
				LK.playMusic(newMusicId, {
					volume: 0,
					loop: true,
					fade: {
						start: 0,
						end: 1 * volumeMultiplier,
						duration: 1000
					}
				});
				// Play scratch sound when BPM changes
				LK.getSound('scratch').play();
				// Update song name display
				if (songNameTxt) {
					var songName = newMusicId.replace(/^\d+BPM/, '');
					songNameTxt.setText(songName);
				}
			}
		}
	}
	// Move beats and check for misses
	for (var i = beats.length - 1; i >= 0; i--) {
		var beat = beats[i];
		// Move beats at constant speed from left to right
		var currentBeatSpeed = getBeatSpeed(); // Always 400 px/s
		// Calculate elapsed time since beat was spawned
		var elapsedTime = songTime - (beat.beatTime - HIT_ZONE_X / currentBeatSpeed);
		// Move beat from left edge at constant speed
		beat.x = elapsedTime * currentBeatSpeed;
		// Ensure beat stays within reasonable bounds
		if (beat.x < -400) {
			beat.x = -400;
		}
		if (beat.x > TIMELINE_X + TIMELINE_WIDTH + 400) {
			beat.x = TIMELINE_X + TIMELINE_WIDTH + 400;
		}
		// Ensure beatMarker always passes below kickTarget
		if (kickTarget && kickTarget.parent) {
			var kickTargetIndex = kickTarget.parent.getChildIndex(kickTarget);
			var beatIndex = beat.parent.getChildIndex(beat);
			if (beatIndex > kickTargetIndex) {
				beat.parent.setChildIndex(beat, kickTargetIndex);
			}
		}
		// Track lastX for miss detection
		if (typeof beat.lastX === "undefined") {
			beat.lastX = beat.x;
		}
		// Only check for miss if the beat has passed the hit zone (not before)
		// Also, do not count as miss if the beat has not yet reached the hit zone at least once
		if (!beat.hit && beat.active && typeof beat.hasReachedHitZone !== "undefined" && beat.hasReachedHitZone && beat.lastX <= HIT_ZONE_X + HIT_WINDOW && beat.x > HIT_ZONE_X + HIT_WINDOW) {
			// Missed
			beat.active = false;
			misses++;
			// Replace the beat marker asset with missCircle for missed beats
			var missedAsset = LK.getAsset('missCircle', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: beat.x,
				// Start from current beat position
				y: beat.y,
				alpha: 0.8,
				width: 60,
				height: 59.77
			});
			// Replace the beat's current asset with missCircle
			if (beat.parent) {
				// Store parent reference before removing beat
				var beatParent = beat.parent;
				// Remove the old beat marker from its parent
				beatParent.removeChild(beat);
				// Add the missed asset to the stored parent reference
				beatParent.addChild(missedAsset);
				// Update the beat reference to point to the new asset
				beats[i] = missedAsset;
				// Copy over important properties
				missedAsset.beatTime = beat.beatTime;
				missedAsset.type = beat.type;
				missedAsset.active = false;
				missedAsset.hit = false;
				missedAsset.lastX = beat.x; // Use current position
				missedAsset.hasReachedHitZone = true;
				missedAsset.isMissed = true; // Mark as missed for special handling
				// Destroy the original beat asset
				beat.destroy();
			}
			// Handle heartshield system
			if (heartshields > 0) {
				// Convert leftmost heartshield to heart (heartshields are lost left to right)
				var shieldIndex = 3 - heartshields; // Get the leftmost heartshield index
				if (heartIcons[shieldIndex]) {
					var parent = heartIcons[shieldIndex].parent;
					if (parent) {
						parent.removeChild(heartIcons[shieldIndex]);
					}
					heartIcons[shieldIndex] = LK.getAsset('heart', {
						anchorX: 0,
						anchorY: 0,
						x: heartStartX + shieldIndex * (heartWidth + heartSpacing),
						y: heartY
					});
					gamescreen.addChild(heartIcons[shieldIndex]);
				}
				heartshields--; // Lose one heartshield
				// No miss feedback, sound, or other penalties for heartshield hits
			} else {
				// All heartshields are gone, now show miss effects and lose hearts
				beat.showFeedback('miss');
				combo = 0;
				perfectCombo = 0; // Reset perfect combo on miss
				// missTxt removed, only hearts for lives
				comboTxt.setText('');
				LK.effects.flashObject(kickTarget, 0xff0000, 200);
				// Play miss sound
				LK.getSound('miss').play();
				// Show MISS feedback text at hit zone
				var missText = new Text2('MISS', {
					size: 20,
					fill: 0xff0000
				});
				missText.scale.set(6, 6);
				missText.anchor.set(0.5, 0.5);
				missText.x = HIT_ZONE_X;
				missText.y = HIT_ZONE_Y - 180;
				game.addChild(missText);
				tween(missText, {
					alpha: 0,
					y: missText.y - 100
				}, {
					duration: 600,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						missText.destroy();
					}
				});
				// Lose a heart and update heart icon (hearts are lost left to right)
				if (lives > 0) {
					var lostIndex = MAX_LIVES - lives; // soldan sağa kaybetmek için
					if (heartIcons[lostIndex]) {
						var parent = heartIcons[lostIndex].parent;
						if (parent) {
							parent.removeChild(heartIcons[lostIndex]);
						}
						heartIcons[lostIndex] = LK.getAsset('lostheart', {
							anchorX: 0,
							anchorY: 0,
							x: heartStartX + lostIndex * (heartWidth + heartSpacing),
							y: heartY
						});
						gamescreen.addChild(heartIcons[lostIndex]);
					}
					lives--;
				}
				if (lives <= 0) {
					gameOver();
				}
			}
		}
		// Track if beat has reached the hit zone at least once
		if (typeof beat.hasReachedHitZone === "undefined") {
			beat.hasReachedHitZone = false;
		}
		if (!beat.hasReachedHitZone && beat.x >= HIT_ZONE_X - HIT_WINDOW) {
			beat.hasReachedHitZone = true;
		}
		// Remove if off screen
		if (beat.x > TIMELINE_X + TIMELINE_WIDTH + 100) {
			beat.destroy();
			beats.splice(i, 1);
		}
		// Update lastX for next frame
		beat.lastX = beat.x;
	}
};
// --- Input handling ---
var isTouching = false;
game.down = function (x, y, obj) {
	if (!gameActive || gamePaused) {
		return;
	}
	// Don't register hits during ready screen
	if (readyContainer.visible) {
		return;
	}
	// Don't register hits when gamescreen is not visible (e.g., in main menu)
	if (!gamescreen.visible) {
		return;
	}
	// Only register if touch is in hit zone
	var dx = x - HIT_ZONE_X;
	var dy = y - HIT_ZONE_Y;
	var dist = Math.sqrt(dx * dx + dy * dy);
	if (dist < 120) {
		isTouching = true;
		// Animate kick target
		kickTarget.destroy();
		kickTarget = LK.getAsset('kickActive', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: HIT_ZONE_X,
			y: HIT_ZONE_Y
		});
		gamescreen.addChild(kickTarget);
		// Check for beat hit
		var hit = false;
		for (var i = 0; i < beats.length; i++) {
			var beat = beats[i];
			if (beat.active && !beat.hit && Math.abs(beat.x - HIT_ZONE_X) < HIT_WINDOW) {
				// Calculate timing accuracy
				var distFromCenter = Math.abs(beat.x - HIT_ZONE_X);
				var feedbackType = '';
				var feedbackText = '';
				var feedbackColor = 0xffffff;
				var scoreAdd = 0;
				if (distFromCenter < 20) {
					feedbackType = 'perfect';
					feedbackText = 'PERFECT!';
					feedbackColor = 0xffe600;
					scoreAdd = 200;
					perfectCount++; // Increment perfect count
					perfectCombo++; // Increment consecutive perfect hits
					if (perfectCombo > maxPerfectCombo) {
						maxPerfectCombo = perfectCombo; // Track maximum consecutive perfect hits
					}
				} else if (distFromCenter < 40) {
					feedbackType = 'awesome';
					feedbackText = 'AWESOME!';
					feedbackColor = 0x00e6ff;
					scoreAdd = 150;
					perfectCombo = 0; // Reset perfect combo for non-perfect hit
				} else if (distFromCenter < 70) {
					feedbackType = 'good';
					feedbackText = 'GOOD';
					feedbackColor = 0x00ff00;
					scoreAdd = 100;
					perfectCombo = 0; // Reset perfect combo for non-perfect hit
				} else {
					feedbackType = 'ok';
					feedbackText = 'OK';
					feedbackColor = 0xcccccc;
					scoreAdd = 50;
					perfectCombo = 0; // Reset perfect combo for non-perfect hit
				}
				beat.hit = true;
				beat.active = false;
				hit = true;
				score += scoreAdd;
				combo += 1;
				if (combo > maxCombo) {
					maxCombo = combo; // Track maximum combo achieved
				}
				LK.setScore(score);
				scoreTxt.setText(score);
				comboTxt.setText('Combo: ' + combo);
				// Show feedback text at hit zone
				var feedbackTxt = new Text2(feedbackText, {
					size: 20,
					fill: feedbackColor
				});
				feedbackTxt.scale.set(6, 6);
				feedbackTxt.anchor.set(0.5, 0.5);
				feedbackTxt.x = HIT_ZONE_X;
				feedbackTxt.y = HIT_ZONE_Y - 180;
				game.addChild(feedbackTxt);
				// Show combo multiplier for perfect hits
				if (feedbackType === 'perfect' && perfectCombo > 1) {
					var comboMultiplierTxt = new Text2('x' + perfectCombo, {
						size: 21,
						fill: 0xff8c00
					});
					comboMultiplierTxt.scale.set(4, 4);
					comboMultiplierTxt.anchor.set(0, 0.5);
					comboMultiplierTxt.x = HIT_ZONE_X + 195;
					comboMultiplierTxt.y = HIT_ZONE_Y - 220;
					game.addChild(comboMultiplierTxt);
					tween(comboMultiplierTxt, {
						alpha: 0,
						y: comboMultiplierTxt.y - 100
					}, {
						duration: 600,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							comboMultiplierTxt.destroy();
						}
					});
				}
				tween(feedbackTxt, {
					alpha: 0,
					y: feedbackTxt.y - 100
				}, {
					duration: 600,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						feedbackTxt.destroy();
					}
				});
				beat.showFeedback('good');
				// Play sounds based on selection - all selected sounds
				if (selectedKickSound !== '') {
					LK.getSound(selectedKickSound).play();
				}
				if (selectedHihatSound !== '') {
					LK.getSound(selectedHihatSound).play();
				}
				if (selectedSnareClapSound !== '') {
					LK.getSound(selectedSnareClapSound).play();
				}
				if (selectedPercussionSound !== '') {
					LK.getSound(selectedPercussionSound).play();
				}
				LK.effects.flashObject(kickTarget, feedbackColor, 200);
				// Replace the beat's current asset based on timing quality while maintaining position and movement
				var newAssetId;
				var tintColor = 0xffffff;
				if (feedbackType === 'perfect') {
					// Perfect hits: perfectcircle asset
					newAssetId = 'perfectcircle';
					tintColor = 0xffffff;
				} else if (feedbackType === 'awesome' || feedbackType === 'good' || feedbackType === 'ok') {
					// Good/awesome/ok hits: green kickActive
					newAssetId = 'kickActive';
					tintColor = 0x00ff00;
				}
				// Replace the beat's visual asset while maintaining its position and movement
				if (beat.parent) {
					// Store parent and current position
					var beatParent = beat.parent;
					var currentX = beat.x;
					var currentY = beat.y;
					// Remove the old beat marker from its parent
					beatParent.removeChild(beat);
					// Create new asset with current position
					var newBeatAsset = LK.getAsset(newAssetId, {
						anchorX: 0.5,
						anchorY: 0.5,
						x: currentX,
						y: currentY,
						tint: tintColor,
						width: 60,
						height: 59.77
					});
					// Add the new asset to the stored parent reference
					beatParent.addChild(newBeatAsset);
					// Update the beat reference to point to the new asset
					beats[i] = newBeatAsset;
					// Copy over important properties
					newBeatAsset.beatTime = beat.beatTime;
					newBeatAsset.type = beat.type;
					newBeatAsset.active = false; // Mark as inactive since it was hit
					newBeatAsset.hit = true;
					newBeatAsset.lastX = currentX;
					newBeatAsset.hasReachedHitZone = true;
					// Destroy the original beat asset
					beat.destroy();
				}
				// BPM remains constant at settings value - no difficulty increase during gameplay
				break;
			}
		}
		if (!hit) {
			// Missed (tapped at wrong time)
			misses++;
			combo = 0;
			perfectCombo = 0; // Reset perfect combo on wrong time
			// missTxt removed, only hearts for lives
			comboTxt.setText('');
			// Play sounds based on selection - all selected sounds
			if (selectedKickSound !== '') {
				LK.getSound(selectedKickSound).play();
			}
			if (selectedHihatSound !== '') {
				LK.getSound(selectedHihatSound).play();
			}
			if (selectedSnareClapSound !== '') {
				LK.getSound(selectedSnareClapSound).play();
			}
			if (selectedPercussionSound !== '') {
				LK.getSound(selectedPercussionSound).play();
			}
			LK.effects.flashObject(kickTarget, 0xff0000, 200);
			// Show WRONG TIME feedback text at hit zone
			var wrongTimeText = new Text2('WRONG TIME', {
				size: 20,
				fill: 0xff4500
			});
			wrongTimeText.scale.set(6, 6);
			wrongTimeText.anchor.set(0.5, 0.5);
			wrongTimeText.x = HIT_ZONE_X;
			wrongTimeText.y = HIT_ZONE_Y - 180;
			game.addChild(wrongTimeText);
			tween(wrongTimeText, {
				alpha: 0,
				y: wrongTimeText.y - 100
			}, {
				duration: 600,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					wrongTimeText.destroy();
				}
			});
			// Only lose a life if countdown is not visible
			if (!countdownContainer.visible) {
				// Handle heartshield system for wrong time hits
				if (heartshields > 0) {
					// Convert leftmost heartshield to heart (heartshields are lost left to right)
					var shieldIndex = 3 - heartshields; // Get the leftmost heartshield index
					if (heartIcons[shieldIndex]) {
						var parent = heartIcons[shieldIndex].parent;
						if (parent) {
							parent.removeChild(heartIcons[shieldIndex]);
						}
						heartIcons[shieldIndex] = LK.getAsset('heart', {
							anchorX: 0,
							anchorY: 0,
							x: heartStartX + shieldIndex * (heartWidth + heartSpacing),
							y: heartY
						});
						gamescreen.addChild(heartIcons[shieldIndex]);
					}
					heartshields--; // Lose one heartshield
					// No miss feedback, sound, or other penalties for heartshield hits
				} else {
					// All heartshields are gone, now lose hearts
					// Lose a life and update heart icon
					if (lives > 0) {
						var lostIndex = MAX_LIVES - lives; // soldan sağa kaybetmek için
						if (heartIcons[lostIndex]) {
							var parent = heartIcons[lostIndex].parent;
							if (parent) {
								parent.removeChild(heartIcons[lostIndex]);
							}
							heartIcons[lostIndex] = LK.getAsset('lostheart', {
								anchorX: 0,
								anchorY: 0,
								x: heartStartX + lostIndex * (heartWidth + heartSpacing),
								y: heartY
							});
							gamescreen.addChild(heartIcons[lostIndex]);
						}
						lives--;
					}
					if (lives <= 0) {
						gameOver();
					}
				}
			}
		}
	}
};
game.up = function (x, y, obj) {
	isTouching = false;
	// Restore kick target
	kickTarget.destroy();
	kickTarget = LK.getAsset('kickTarget', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: HIT_ZONE_X,
		y: HIT_ZONE_Y
	});
	gamescreen.addChild(kickTarget);
};
// --- Game over ---
function gameOver() {
	gameActive = false;
	LK.effects.flashScreen(0xff0000, 800);
	showDefeatScreen();
	LK.stopMusic();
}
// --- Glow Effect for Purple Elements ---
function addGlowEffect(element, glowColor, intensity) {
	if (!element || !element.visible) {
		return;
	}
	// Create glow animation using tint and alpha
	var originalTint = element.tint || 0xffffff;
	var glowTint = glowColor || 0xaa00ff; // Default purple glow
	var glowIntensity = intensity || 0.3;
	// Pulsing glow effect
	function startGlow() {
		tween(element, {
			alpha: 1 - glowIntensity
		}, {
			duration: 800,
			easing: tween.easeInOut,
			yoyo: true,
			repeat: -1 // Infinite repeat
		});
	}
	startGlow();
}
// Apply glow to purple elements
function applyGlowToVioletElements() {
	// Apply glow to kick target (blue/violet color)
	if (kickTarget) {
		addGlowEffect(kickTarget, 0x8a2be2, 0.2);
	}
	// Apply glow to main menu buttons (purple/violet elements)
	if (startBtn) {
		addGlowEffect(startBtn, 0x8a2be2, 0.15);
	}
	if (settingsBtn) {
		addGlowEffect(settingsBtn, 0x8a2be2, 0.15);
	}
	if (creditsBtn) {
		addGlowEffect(creditsBtn, 0x8a2be2, 0.15);
	}
	if (supportBtn) {
		addGlowEffect(supportBtn, 0x8a2be2, 0.15);
	}
	// Apply glow to BPM circle container if it exists
	if (typeof bpmCircleContainer !== 'undefined' && bpmCircleContainer) {
		addGlowEffect(bpmCircleContainer, 0x8a2be2, 0.2);
	}
}
// Initialize glow effects
applyGlowToVioletElements();
// --- Win condition ---
function checkWin() {
	if (score >= 5000) {
		gameActive = false;
		LK.effects.flashScreen(0x00ff00, 800);
		LK.showYouWin();
		LK.stopMusic();
	}
}
// --- Defeat Screen Implementation ---
var defeatContainer = new Container();
defeatContainer.visible = false;
game.addChild(defeatContainer);
var maxCombo = 0; // Track maximum combo achieved
var perfectCount = 0; // Track number of perfect hits
var perfectCombo = 0; // Track current consecutive perfect hits
var maxPerfectCombo = 0; // Track maximum consecutive perfect hits
var lastBpmUpgradeScore = 0; // Track last score where BPM was upgraded
var gamePaused = false; // Track if game is paused
var pauseContainer = new Container();
pauseContainer.visible = false;
game.addChild(pauseContainer);
function showDefeatScreen() {
	defeatContainer.visible = true;
	defeatContainer.removeChildren();
	gamescreen.visible = false;
	bpmDisplayTxt.visible = false;
	songNameTxt.visible = false;
	// Add defeat background using defeatbg asset
	var defeatBg = LK.getAsset('defeatbg', {
		anchorX: 0,
		anchorY: 0,
		x: 0,
		y: 0,
		width: 2048,
		height: 2732
	});
	defeatContainer.addChild(defeatBg);
	// Add blurred background behind statistics
	var blurredBg = LK.getAsset('blurred', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 1235,
		scaleX: 1.35,
		scaleY: 1.35,
		alpha: 1
	});
	defeatContainer.addChild(blurredBg);
	// Game Over title using gameover asset
	var gameOverAsset = LK.getAsset('gameover', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 600,
		scaleX: 8,
		scaleY: 8
	});
	defeatContainer.addChild(gameOverAsset);
	// Statistics arranged vertically with 5px spacing
	var statsStartY = 990;
	var statsSpacing = 5;
	var currentY = statsStartY;
	// Score display
	var finalScoreTxt = new Text2("Score: " + score, {
		size: 18,
		fill: 0xffffff
	});
	finalScoreTxt.scale.set(6, 6);
	finalScoreTxt.anchor.set(0, 0.5);
	finalScoreTxt.x = 2048 / 2 - 550;
	finalScoreTxt.y = currentY;
	defeatContainer.addChild(finalScoreTxt);
	currentY += finalScoreTxt.height + statsSpacing;
	// Max combo display
	var maxComboTxt = new Text2("Max Combo: " + maxCombo, {
		size: 18,
		fill: 0x00ff00
	});
	maxComboTxt.scale.set(6, 6);
	maxComboTxt.anchor.set(0, 0.5);
	maxComboTxt.x = 2048 / 2 - 550;
	maxComboTxt.y = currentY;
	defeatContainer.addChild(maxComboTxt);
	currentY += maxComboTxt.height + statsSpacing;
	// Perfect count display
	var perfectCountTxt = new Text2("Perfect: " + perfectCount, {
		size: 18,
		fill: 0xffe600
	});
	perfectCountTxt.scale.set(6, 6);
	perfectCountTxt.anchor.set(0, 0.5);
	perfectCountTxt.x = 2048 / 2 - 550;
	perfectCountTxt.y = currentY;
	defeatContainer.addChild(perfectCountTxt);
	currentY += perfectCountTxt.height + statsSpacing;
	// Max perfect combo display (orange color)
	var maxPerfectComboTxt = new Text2("Max Perfect Combo: " + maxPerfectCombo, {
		size: 18,
		fill: 0xff8c00
	});
	maxPerfectComboTxt.scale.set(6, 6);
	maxPerfectComboTxt.anchor.set(0, 0.5);
	maxPerfectComboTxt.x = 2048 / 2 - 550;
	maxPerfectComboTxt.y = currentY;
	defeatContainer.addChild(maxPerfectComboTxt);
	// Calculate button positions
	var defeatButtonStartY = 1700;
	var defeatButtonHeight = 289;
	var defeatButtonSpacing = 20;
	// Tekrar Oyna (Play Again) Button
	var playAgainBtn = LK.getAsset('tryagain', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: defeatButtonStartY,
		scaleX: 5,
		scaleY: 5
	});
	defeatContainer.addChild(playAgainBtn);
	// Ana Menü (Main Menu) Button
	var mainMenuBtn = LK.getAsset('mainmenu', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: defeatButtonStartY + defeatButtonHeight + defeatButtonSpacing,
		scaleX: 5,
		scaleY: 5
	});
	defeatContainer.addChild(mainMenuBtn);
	// Button event handlers
	playAgainBtn.down = function (x, y, obj) {
		// Play button click sound
		LK.getSound('buttonclick').play();
		// Click animation
		tween(playAgainBtn, {
			scaleX: 4.5,
			scaleY: 4.5
		}, {
			duration: 80,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				tween(playAgainBtn, {
					scaleX: 5,
					scaleY: 5
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						defeatContainer.visible = false;
						maxCombo = 0; // Reset max combo
						perfectCount = 0; // Reset perfect count
						maxPerfectCombo = 0; // Reset max perfect combo
						showReadyScreen(function () {
							showCountdown(function () {
								startGame();
							});
						});
					}
				});
			}
		});
	};
	mainMenuBtn.down = function (x, y, obj) {
		// Play button click sound
		LK.getSound('buttonclick').play();
		// Click animation
		tween(mainMenuBtn, {
			scaleX: 4.5,
			scaleY: 4.5
		}, {
			duration: 80,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				tween(mainMenuBtn, {
					scaleX: 5,
					scaleY: 5
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						defeatContainer.visible = false;
						maxCombo = 0; // Reset max combo
						perfectCount = 0; // Reset perfect count
						maxPerfectCombo = 0; // Reset max perfect combo
						mainMenuContainer.visible = true;
						scoreTxt.visible = false;
						comboTxt.visible = false;
						bpmDisplayTxt.visible = false;
						songNameTxt.visible = false;
						gamescreen.visible = false;
						// Stop current music and play menu music with a small delay to ensure proper playback (only if not muted)
						LK.stopMusic();
						if (!musicMuted) {
							LK.setTimeout(function () {
								var volumeMultiplier = soundVolume / 100;
								LK.playMusic('menumusic', {
									volume: 0.8 * volumeMultiplier,
									loop: true
								});
							}, 100);
						}
					}
				});
			}
		});
	};
}
// --- Restart on game over ---
LK.on('gameover', function () {
	showDefeatScreen();
});
LK.on('youwin', function () {
	startGame();
}); ===================================================================
--- original.js
+++ change.js
@@ -61,18 +61,18 @@
 
 /**** 
 * Game Code
 ****/ 
-// --- BPM-specific music assets (kickless versions) ---
-// Music (looping, short demo)
-// Sound for kick
-// Good feedback
-// Miss feedback
-// Beat marker
-// Timeline bar
-// Bass drum (kick) hit circle when active
-// Bass drum (kick) hit circle
 // --- Game constants ---
+// Bass drum (kick) hit circle
+// Bass drum (kick) hit circle when active
+// Timeline bar
+// Beat marker
+// Miss feedback
+// Good feedback
+// Sound for kick
+// Music (looping, short demo)
+// --- BPM-specific music assets (kickless versions) ---
 var TIMELINE_WIDTH = 2048;
 var TIMELINE_HEIGHT = 25;
 var TIMELINE_Y = 2000; // Y position of timeline bar
 var TIMELINE_X = 0;
@@ -1734,8 +1734,11 @@
 // Show pause menu function
 function showPauseMenu() {
 	pauseContainer.visible = true;
 	pauseContainer.removeChildren();
+	// Hide BPM and song name in pause menu
+	bpmDisplayTxt.visible = false;
+	songNameTxt.visible = false;
 	// Pause menu background
 	var pauseMenuBg = LK.getAsset('pausemenu', {
 		anchorX: 0,
 		anchorY: 0,
@@ -1909,8 +1912,11 @@
 // Resume game function
 function resumeGame() {
 	gamePaused = false;
 	pauseContainer.visible = false;
+	// Show BPM and song name when resuming
+	bpmDisplayTxt.visible = true;
+	songNameTxt.visible = true;
 	lastTickTime = Date.now(); // Reset time to prevent time jump
 }
 // --- Beat spawning ---
 function spawnBeat(beat) {
 empty heart
 A 2048x2732 vertical pixel art background for the main menu of a rhythm game. The scene shows a moody, neon-lit cityscape at night through a big window behind a cozy, minimal DJ setup. The foreground includes soft lights, vinyl records, and glowing cables. Background buildings feature soft pulsing lights and pixel-style clouds or stars. The mood is dreamy, lo-fi, and rhythmic, with purple, indigo, and cyan tones. No characters or text, just a calm and stylish menu background.. In-Game asset. 2d. High contrast. No shadows
 A 2048x2732 vertical pixel art background for a settings screen in a pixel-art rhythm game. The scene shows a cozy side corner of the same DJ studio seen in the main menu, with shelves full of vinyls, tangled audio cables, studio monitors, and an analog BPM dial glowing softly. A small desk lamp casts a warm light over a notepad and some buttons. The lighting is purple and blue, calm and focused. The mood is quiet, technical, and slightly futuristic — perfect for adjusting settings.. In-Game asset. 2d. High contrast. No shadows
 A 2048x2732 vertical pixel art background for a credits screen in a rhythm-based pixel art game. The scene shows a cozy wall in the same neon-lit DJ studio, filled with pinned polaroid photos, signed posters, music flyers, sticky notes, and handwritten thank-you notes. Soft glowing fairy lights hang above. The lighting is soft pink, violet and blue, with a nostalgic, emotional, and heartfelt vibe. No characters or UI — just a decorative wall filled with creative memories and gratitude.. In-Game asset. 2d. High contrast. No shadows
 A single rectangular pixel art button labeled “Start” in a purple neon tone, designed for a lo-fi rhythm-based pixel art game. The button has soft glowing edges, a subtle pixel shadow, and a clean 1-bit pixel font. The overall mood is cozy and dreamy, matching a neon-lit DJ studio aesthetic. The background should be transparent.. In-Game asset. 2d. High contrast. No shadows
 Write SETTINGS instead of START.
 Write CREDITS instead of START.
 Write SUPPORT US instead of SETTINGS.
 A bold and stylish pixel art logo text for the game title “DJ RHYTHMCOLIC” designed for a lo-fi rhythm pixel art game. The text is large, vibrant purple with neon glow effects, featuring a retro pixel font that looks futuristic and energetic. Behind the text, subtle pixelated neon sound waves and small music notes float gently in purple and blue hues, blending with a cozy DJ studio atmosphere. The background is transparent or very dark to highlight the glowing title. The style matches a dreamy, neon-lit nighttime vibe with pixel-perfect detail.. In-Game asset. 2d. High contrast. No shadows
 yellow ball pixel-art. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
 A minimalist horizontal pixel art timeline bar, 2048x40 resolution, designed for a lo-fi rhythm pixel game. The bar is sleek and thin, with subtle purple and violet tones, no numbers or markers. The style is consistent with a DJ-themed interface — soft glowing edges, pixel-perfect precision, and no background (transparent). The bar should feel modern yet retro, fitting into a dreamy neon-lit rhythm game UI.. In-Game asset. 2d. High contrast. No shadows
 A pixel art arrow starting from a glowing "TAP" label in retro pixel font, pointing diagonally from the bottom right toward the upper left, as if guiding the player to tap that area. The arrow is sleek, with a smooth curve or angled segments, styled in purple or violet neon tones with a soft glow effect. The design matches a lo-fi rhythm game aesthetic. The "TAP" label is positioned at the tail of the arrow and glows subtly. No background — transparent.. In-Game asset. 2d. High contrast. No shadows
 A pixel art button with the word "READY" written in bold, retro pixel font. The button is rectangular with slightly rounded corners, styled in purple and violet tones with a soft glowing border to match a lo-fi rhythm game's aesthetic. The "READY" text is centered, white or light-colored for contrast, with pixel-perfect sharpness. The button has a slightly raised 3D appearance and no background (transparent). Designed for use in a minimalist, neon-themed rhythm game UI.. In-Game asset. 2d. High contrast. No shadows
 A cozy pixel art bar interior viewed from the DJ's perspective. A dimly lit, moody atmosphere with purple and deep blue neon tones. Visible DJ desk with mixer and speakers in the foreground, blurred bar counter and patrons in the background. Small glowing lights, bottles on shelves, soft lighting, and retro vibes. Resolution: 2048x2732. No characters in front, focus on ambiance and depth.. In-Game asset. 2d. High contrast. No shadows
 pixel-art purple heart. In-Game asset. 2d. High contrast. No shadows
 heart with blue shield
 A transparent background pixel art UI table showing game credits. Each credit line is inside a separate softly glowing purple pixel-style rectangular box. Pixel font text is centered in each box and reads: "Credits" "Tasarım & Kod: FRVR.Ava.Combo[POGAAS].v1.0" "Inspired by Ada Lovelace" "Prompt Engineering by cielique" No background or shadows. Only the pixel table with glowing boxes and readable pixel-style text. Maintain a clean, retro-modern design suitable for overlaying on a DJ bar scene. Resolution: 2048x2732, vertically aligned.. In-Game asset. 2d. High contrast. No shadows
 A transparent background pixel art UI panel with "Support Us" title and a list of support actions. Each action is inside a separate glowing purple pixel-style rectangular box. Centered pixel font for text. The boxes are aligned vertically, styled like a clean UI overlay, no background or shadows. Resolution: 2048x2732. Text inside each box: "Support Us" "→ Upvote the game" "→ Share with your friends" "→ Leave a comment" "→ Send us your ideas" The overall design should feel fun, inviting, and in harmony with a DJ rhythm game's UI theme.. In-Game asset. 2d. High contrast. No shadows
 A 2048x2732 vertical pixel art background for a “Support Us” screen in a rhythm-based pixel art game. The scene continues the cozy neon-lit DJ room theme from the main menu, but zooms in slightly on the desk. A pixel-art tip jar labeled “Thank you!”, a laptop covered in music-themed stickers, coffee mugs, and glowing synth equipment are visible. Lighting remains dreamy and lo-fi with purples and soft blues. The mood feels warm, humble, and inviting. No characters or text — just the environment.. In-Game asset. 2d. High contrast. No shadows. In-Game asset. 2d. High contrast. No shadows
 Pixel art “Try Again” button, retro arcade style, purple tones, soft shadows, chunky text, fits rhythm game UI.. In-Game asset. 2d. High contrast. No shadows
 change text with MAIN MENU
 Pixel art “Game Over” text, bold retro arcade style, purple tones, glitch-free, clean and dramatic for rhythm game UI.. In-Game asset. 2d. High contrast. No shadows
 Pixel art background, 2048x2732 resolution, defeat screen for a rhythm game set in a moody bar. Dim lighting, purple and dark tones, empty DJ booth, quiet atmosphere, no characters or text.. In-Game asset. 2d. High contrast. No shadows
 
 orange
 CLOSE
 purple
 daha koyu mor ve köşeler daha yuvarlak
 soft edge square, violet purple, pixel art. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
 
 Pixel art tutorial table UI, clean layout with text blocks, purple-themed, 8-bit retro style, no background, no icons, fits game start screen "[How to Play] • Tap the button in time with the rhythm! • Earn points and combos by staying on beat. • Want to change speed or volume? → Check out the Settings menu for BPM & sound options. Get ready to groove!". In-Game asset. 2d. High contrast. No shadows
 Pixel art pause button, purple color, rounded corners, 8-bit UI style, minimal design, no background, 80x80 size, suitable for mobile rhythm game interface. In-Game asset. 2d. High contrast. No shadows
 A minimalist pixel art "Paused" menu screen in vertical format (2048x2732), with a retro DJ/bar theme. At the top center, the word "PAUSED" in large, glowing purple pixel letters. The rest of the screen should be clean and dark, with subtle lighting or atmospheric effects suggesting a nightclub or DJ booth. Leave the central and lower space empty for placing UI buttons (Resume, Restart, Settings, Main Menu). Smooth, moody pixel background, matching a futuristic arcade vibe.. In-Game asset. 2d. High contrast. No shadows
 change text with RESUME
 change text with RESTART
kick
Sound effect
miss
Sound effect
menumusic
Music
75BPMElectricDreams
Music
80BPMNeonNights
Music
85BPMCyberFlow
Music
90BPMDigitalPulse
Music
95BPMFutureBass
Music
100BPMSynthWave
Music
40BPMDeepVibes
Music
45BPMChillWave
Music
50BPMSlowMotion
Music
55BPMDreamscape
Music
60BPMLowKey
Music
65BPMRelaxed
Music
70BPMCalmVibes
Music
105BPMHyperDrive
Music
110BPMTechnoRush
Music
115BPMHighEnergy
Music
120BPMMaximum
Music
scratch
Sound effect
buttonclick
Sound effect
kick2
Sound effect
kick3
Sound effect
kick4
Sound effect
hihat
Sound effect
hihat2
Sound effect
hihat3
Sound effect
hihat4
Sound effect
snareclap
Sound effect
snareclap2
Sound effect
snareclap3
Sound effect
snareclap4
Sound effect
percussion
Sound effect
percussion2
Sound effect
percussion3
Sound effect
percussion4
Sound effect
thanks
Sound effect