User prompt
İlk başta hiç insan olmasın.
User prompt
Oyunda en fazla 10 insan doğabilsin her insan %10 Popularity sağlasın.
User prompt
Erkanın tam ortasında bir çizgi olsun bu çizgi dışında ekranın en sağında ve en solunda sadece insan çıksın o çizgide insanlar doğamasın.
User prompt
Davul aseti insan asetinin önünde olsun yani eğer davulun üstünde insanlar davulub arkasında olsun.
User prompt
İnsanlar 2 saniye notalara dokunmayınca hareket etme özelliğini kaldır.
User prompt
Davulun etrafındaki kalkanda insanlar doğamasınlar.
User prompt
Davulun etrafındaki kalkan görünmez olsun ama hayla işe yaramaya devam etsin yani insanlar hayla o kareyi geçemesinler.
User prompt
Please fix the bug: 'ReferenceError: leftShieldKare is not defined' in or related to this line: 'if (leftShieldKare && leftShieldKare.containsPerson(peopleLeft[i])) {' Line Number: 1691
User prompt
Davulun etrafında bir kare kalkan olsun insanlar buraya deyince farklı bir yere ışınlansınlar.
User prompt
İnsanlar davulun üstünde doğmasınlar sadece etrafta doğabilsinler.
User prompt
X şekli olsun şuan öyle değil direk x olsun yani.
User prompt
10 bin puandan sonra 2 tane lane silinsin sadece iki tane lane kalsın bunlarda x şeklinde dursun ve ekranın ortasına kadar uzasın.
User prompt
Lanelar 10 bin puandan sonra x şekline gelsinler ve notalar ona göre spawn olmaya başlasınlar.
User prompt
Notalar laneların olduğu yerlere göre çıksınlar yani lanelar hareket ettikleri zaman laneların hareket ettikleri yerleri takip etsinler yukardan gelmeye devam etsinler.
User prompt
İnsanların boyutlarını birazcık büyüt.
User prompt
Laneları çok azıcık genişlet.
User prompt
Notaların genişliğini 175 yap.
User prompt
Notaların genişliğini 170 yap hepsinin.
User prompt
Notalar lanelar büyüklüğünde olsunlar yani genişlik olarak uzunluk olarka değil.
User prompt
Ekranın sol altına high score yaz.
User prompt
Her nota kaçırdığımızda 2% Popularity düşsün ve bir insan silinsin.
User prompt
Popularity yazısı ekranda gözükmüyor bunu düzelt.
User prompt
Ekranın sağ altında Popularity yazsın bu yüzdeliğe göre örneğin %10 gibi popularity ise insan sayısı belirlicek her insan %2 popülerlik sağlasın ve her insan arttığında popülerlik artsın.
User prompt
Davulu vurunca ekrana gelen sallanma efekti her zaman olsun yani comboya göre gücü azalmasın gücü her zaman öyle olsun.
User prompt
İnsanların zıplayınca ekrana yarattığı sallanma efekti davula vurunca daha fazla olsun.
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	highScore: 0
});
/**** 
* Classes
****/ 
// DrumNote class for notes on drums
var DrumNote = Container.expand(function () {
	var self = Container.call(this);
	self.spawnTime = 0;
	self.isLeft = true;
	self.hit = false;
	self.lifeTime = 300; // 5 seconds at 60fps
	var noteGraphics = self.attachAsset('drumNote', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Add a timer text above the note
	self.timerText = new Text2('3.0', {
		size: 60,
		fill: 0xFF2222,
		font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
	});
	self.timerText.anchor.set(0.5, 1); // center, bottom
	self.timerText.x = 0;
	self.timerText.y = -noteGraphics.height / 2 - 10;
	self.addChild(self.timerText);
	self.update = function () {
		// Update timer text if not hit
		if (!self.hit) {
			var elapsed = songTicks - self.spawnTime;
			var remain = Math.max(0, (self.lifeTime - elapsed) / 60);
			// Show with 1 decimal, clamp to 0
			self.timerText.setText(remain.toFixed(1));
		}
		if (!self.hit && songTicks - self.spawnTime > self.lifeTime) {
			// Note expired - game over
			LK.showGameOver();
		}
	};
	self.onHit = function () {
		if (self.hit) return;
		self.hit = true;
		// Explosion effect
		var particleCount = 6;
		var colors = [0xFFD700, 0xFFAA00, 0xFFFF00];
		for (var p = 0; p < particleCount; p++) {
			var particle = LK.getAsset('centerCircle', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: self.x,
				y: self.y,
				width: 30 + Math.random() * 40,
				height: 30 + Math.random() * 40
			});
			particle.tint = colors[Math.floor(Math.random() * colors.length)];
			if (self.parent) self.parent.addChild(particle);
			var angle = Math.PI * 2 * p / particleCount;
			var distance = 100 + Math.random() * 100;
			var targetX = self.x + Math.cos(angle) * distance;
			var targetY = self.y + Math.sin(angle) * distance;
			tween(particle, {
				x: targetX,
				y: targetY,
				alpha: 0,
				scaleX: 0.1,
				scaleY: 0.1
			}, {
				duration: 400,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					if (particle.parent) particle.destroy();
				}
			});
		}
		tween(self, {
			alpha: 0,
			scaleX: 1.5,
			scaleY: 1.5
		}, {
			duration: 200,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
	};
	return self;
});
// Note class for falling notes
var Note = Container.expand(function () {
	var self = Container.call(this);
	// Lane index (0-3)
	self.lane = 0;
	self.hit = false;
	self.missed = false;
	self.speed = 0; // pixels per tick
	self.time = 0; // time (in ticks) when note should reach the target
	self.spawned = false;
	// Attach correct note asset based on lane
	self.setLane = function (laneIdx) {
		self.lane = laneIdx;
		var assetId = 'note' + (laneIdx + 1);
		var noteAsset = self.attachAsset(assetId, {
			anchorX: 0.5,
			anchorY: 0.5,
			width: NOTE_WIDTH,
			height: NOTE_HEIGHT
		});
	};
	// Called every tick
	self.update = function () {
		if (!self.spawned) return;
		self.y += self.speed;
		// Follow lane container movement
		if (self.laneContainer) {
			self.x = self.laneContainer.x;
		}
	};
	// Called when note is hit
	self.onHit = function () {
		if (self.hit || self.missed) return;
		self.hit = true;
		// Create explosion effect with particles
		var particleCount = 8;
		var colors = [0xFFD700, 0xFF4444, 0x44FF44, 0x4444FF, 0xFF44FF, 0x44FFFF];
		for (var p = 0; p < particleCount; p++) {
			var particle = LK.getAsset('centerCircle', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: self.x,
				y: self.y,
				width: 20 + Math.random() * 30,
				height: 20 + Math.random() * 30
			});
			particle.tint = colors[Math.floor(Math.random() * colors.length)];
			if (self.parent) self.parent.addChild(particle);
			// Random direction for explosion
			var angle = Math.PI * 2 * p / particleCount + (Math.random() - 0.5) * 0.5;
			var distance = 80 + Math.random() * 120;
			var targetX = self.x + Math.cos(angle) * distance;
			var targetY = self.y + Math.sin(angle) * distance;
			// Animate particle explosion
			tween(particle, {
				x: targetX,
				y: targetY,
				alpha: 0,
				scaleX: 0.2,
				scaleY: 0.2
			}, {
				duration: 300 + Math.random() * 200,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					if (particle.parent) particle.destroy();
				}
			});
		}
		// Animate note
		tween(self, {
			alpha: 0,
			scaleX: 1.5,
			scaleY: 1.5
		}, {
			duration: 150,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
	};
	// Called when note is missed
	self.onMiss = function () {
		if (self.hit || self.missed) return;
		self.missed = true;
		LK.getSound('miss').play({
			fade: {
				start: 1,
				end: 0,
				duration: 1000
			}
		});
		tween(self, {
			alpha: 0
		}, {
			duration: 200,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
	};
	return self;
});
// People class for animated people at lane edges
var People = Container.expand(function () {
	var self = Container.call(this);
	self.isJumping = false;
	self.baseY = 0;
	self.personType = Math.floor(Math.random() * 5); // Random type 0-4
	// Create different visual styles based on person type
	var body;
	switch (self.personType) {
		case 0:
			// Type 1: Tall blue person
			body = self.attachAsset('centerCircle', {
				anchorX: 0.5,
				anchorY: 1,
				width: 110,
				height: 240,
				y: 0,
				tint: 0x3366FF
			});
			break;
		case 1:
			// Type 2: Wide green person
			body = self.attachAsset('centerCircle', {
				anchorX: 0.5,
				anchorY: 1,
				width: 150,
				height: 200,
				y: 0,
				tint: 0x33FF66
			});
			break;
		case 2:
			// Type 3: Medium red person
			body = self.attachAsset('centerCircle', {
				anchorX: 0.5,
				anchorY: 1,
				width: 125,
				height: 220,
				y: 0,
				tint: 0xFF3366
			});
			break;
		case 3:
			// Type 4: Small yellow person
			body = self.attachAsset('centerCircle', {
				anchorX: 0.5,
				anchorY: 1,
				width: 100,
				height: 170,
				y: 0,
				tint: 0xFFFF33
			});
			break;
		case 4:
			// Type 5: Average purple person
			body = self.attachAsset('centerCircle', {
				anchorX: 0.5,
				anchorY: 1,
				width: 120,
				height: 210,
				y: 0,
				tint: 0xCC33FF
			});
			break;
	}
	// Arms removed: only body remains
	// Save baseY for jump animation
	self.baseY = self.y;
	// Animate jump
	self.jump = function () {
		if (self.isJumping) return;
		self.isJumping = true;
		var jumpHeight = 120;
		var jumpDuration = 180;
		var originalY = self.y;
		// --- Screen shake effect when people jump ---
		if (typeof game !== "undefined" && typeof tween !== "undefined") {
			// Only shake if not already shaking
			if (!game._isShaking) {
				game._isShaking = true;
				var originalGameX = game.x || 0;
				var originalGameY = game.y || 0;
				// Determine if all people are jumping at once for stronger shake
				var allJumping = false;
				if (typeof peopleLeft !== "undefined" && typeof peopleRight !== "undefined") {
					var allLeftJumping = true;
					for (var i = 0; i < peopleLeft.length; i++) {
						if (!peopleLeft[i].isJumping) {
							allLeftJumping = false;
							break;
						}
					}
					var allRightJumping = true;
					for (var i = 0; i < peopleRight.length; i++) {
						if (!peopleRight[i].isJumping) {
							allRightJumping = false;
							break;
						}
					}
					allJumping = allLeftJumping && allRightJumping;
				}
				var shakeAmount = allJumping ? 120 : 40; // much stronger shake if all people are jumping
				var shakeDuration = allJumping ? 260 : 180;
				// Shake out
				tween(game, {
					x: originalGameX + (Math.random() - 0.5) * shakeAmount,
					y: originalGameY + (Math.random() - 0.5) * shakeAmount
				}, {
					duration: shakeDuration,
					onFinish: function onFinish() {
						// Shake back
						tween(game, {
							x: originalGameX,
							y: originalGameY
						}, {
							duration: shakeDuration,
							onFinish: function onFinish() {
								game._isShaking = false;
							}
						});
					}
				});
			}
		}
		tween(self, {
			y: originalY - jumpHeight
		}, {
			duration: jumpDuration,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(self, {
					y: originalY
				}, {
					duration: jumpDuration,
					easing: tween.easeIn,
					onFinish: function onFinish() {
						self.isJumping = false;
					}
				});
			}
		});
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181818
});
/**** 
* Game Code
****/ 
// Notes are destroyed by tapping them directly before they reach the white target area at the bottom
// 4 note lanes, each with a different color for clarity
// --- UI Elements ---
var NUM_LANES = 4;
var LANE_WIDTH = 230;
var LANE_SPACING = 40;
var NOTE_WIDTH = 340; // Wider notes
var NOTE_HEIGHT = 340; // Taller notes (stretches upward)
var TARGET_HEIGHT = 60; // White target area is now just a visual "danger" zone, reduced height for smaller targets
var LANE_HEIGHT = 2200;
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var LANE_TOTAL_WIDTH = NUM_LANES * LANE_WIDTH + (NUM_LANES - 1) * LANE_SPACING;
var LANE_START_X = (GAME_WIDTH - LANE_TOTAL_WIDTH) / 2 + LANE_WIDTH / 2;
var TARGET_Y = GAME_HEIGHT - 420; // Target zone Y position (moved higher)
// --- Game State ---
var notes = []; // All active notes
var noteIndex = 0; // Index of next note to spawn
var songTicks = 0; // Ticks since song start
var score = 0;
var combo = 0;
var maxCombo = 0;
var misses = 0;
var maxMisses = 10;
var songEnded = false;
var songStarted = false;
var lastTick = 0;
// Note speed multiplier for gradual speed up
var noteSpeedMultiplier = 1.0;
// Lane color flashing state
var laneColorFlashActive = false;
var laneColorFlashStartTime = 0;
var laneColorFlashTriggered = false;
// Drum variables
var leftDrum = null;
var rightDrum = null;
var drumNotes = [];
var drumsActive = false;
var nextDrumNoteTime = 0;
// --- UI Elements ---
var scoreTxt = new Text2('0', {
	size: 120,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// High Score UI
// --- Per-mode high score keys ---
function getCurrentModeKey() {
	if (typeof extremeMode !== "undefined" && extremeMode) return "extreme";
	if (typeof hardMode !== "undefined" && hardMode) return "hard";
	return "easy";
}
function getHighScoreKey() {
	return "highScore_" + getCurrentModeKey();
}
function getHighScore() {
	var key = getHighScoreKey();
	return typeof storage[key] !== "undefined" ? storage[key] : 0;
}
function setHighScore(val) {
	var key = getHighScoreKey();
	storage[key] = val;
}
var highScore = getHighScore();
var highScoreTxt = new Text2('High Score: ' + highScore, {
	size: 60,
	fill: 0xFFD700
});
// Move high score to top-right, with some margin from the edge
highScoreTxt.anchor.set(1, 0); // right aligned, top
highScoreTxt.x = LK.gui.width - 40; // 40px margin from right
highScoreTxt.y = 30; // 30px from top
LK.gui.top.addChild(highScoreTxt);
var comboTxt = new Text2('', {
	size: 70,
	fill: 0xFFE066
});
comboTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(comboTxt);
comboTxt.y = 130;
// --- Popularity Display ---
var popularityTxt = new Text2('Popularity: 0%', {
	size: 60,
	fill: 0xFFD700
});
popularityTxt.anchor.set(1, 1); // right aligned, bottom
popularityTxt.x = GAME_WIDTH - 40; // 40px margin from right
popularityTxt.y = GAME_HEIGHT - 40; // 40px margin from bottom
game.addChild(popularityTxt);
// --- High Score Display in Bottom Left ---
var bottomHighScoreTxt = new Text2('High Score: ' + getHighScore(), {
	size: 60,
	fill: 0xFFD700
});
bottomHighScoreTxt.anchor.set(0, 1); // left aligned, bottom
bottomHighScoreTxt.x = 40; // 40px margin from left
bottomHighScoreTxt.y = GAME_HEIGHT - 40; // 40px margin from bottom
game.addChild(bottomHighScoreTxt);
// Function to update popularity based on total people count
function updatePopularity() {
	var totalPeople = peopleLeft.length + peopleRight.length;
	var popularity = Math.min(totalPeople * 10, 100); // Each person is 10%, cap at 100%
	popularityTxt.setText('Popularity: ' + popularity + '%');
}
// --- Mode Labels ---
var hardMode = typeof hardMode !== "undefined" ? hardMode : false;
var extremeMode = typeof extremeMode !== "undefined" ? extremeMode : false;
var hardModeLabel = null;
var extremeModeLabel = null;
if (extremeMode) {
	extremeModeLabel = new Text2('EXTREME MODE', {
		size: 80,
		fill: 0xFF00FF,
		font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
	});
	extremeModeLabel.anchor.set(0.5, 0);
	extremeModeLabel.x = GAME_WIDTH / 2;
	extremeModeLabel.y = 40;
	LK.gui.top.addChild(extremeModeLabel);
} else if (hardMode) {
	hardModeLabel = new Text2('HARD MODE', {
		size: 80,
		fill: 0xFF2222,
		font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
	});
	hardModeLabel.anchor.set(0.5, 0);
	hardModeLabel.x = GAME_WIDTH / 2;
	hardModeLabel.y = 40;
	LK.gui.top.addChild(hardModeLabel);
}
// Removed red 'misses' text from the top GUI. Misses are now only shown in white below each target.
// --- Add Background ---
var background = LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: GAME_WIDTH,
	height: GAME_HEIGHT
});
game.addChild(background);
// --- Lanes and Targets ---
var lanes = [];
var targets = [];
var peopleLeft = [];
var peopleRight = [];
var currentPeoplePerSide = 0; // Track current number of people per side
var lastScoreMilestone = 0; // Track last score milestone for adding people
var targetMissTexts = []; // Miss counters for each target
var laneContainers = []; // Containers to group lane elements together
for (var i = 0; i < NUM_LANES; i++) {
	// Create a container for each lane to group all elements
	var laneContainer = new Container();
	var laneX = LANE_START_X + i * (LANE_WIDTH + LANE_SPACING);
	laneContainer.x = laneX;
	laneContainer.baseX = laneX; // Store base position for movement
	game.addChild(laneContainer);
	laneContainers.push(laneContainer);
	// Lane background
	var lane = LK.getAsset('lane', {
		anchorX: 0.5,
		anchorY: 0,
		x: 0,
		//{2r} // Relative to container
		y: 0,
		width: LANE_WIDTH,
		height: LANE_HEIGHT
	});
	laneContainer.addChild(lane);
	lanes.push(lane);
	// Visually improved target: larger, more distinct, with a colored border effect
	var target = LK.getAsset('target', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		//{2w} // Relative to container
		y: TARGET_Y + 40,
		//{1R} // Move target further back (higher y = lower on screen)
		width: LANE_WIDTH + 40,
		// Make target slightly wider for better visuals
		height: TARGET_HEIGHT + 40 // Make target slightly taller for better visuals
	});
	laneContainer.addChild(target);
	// Add a second, inner target for a "bullseye" effect
	var innerTarget = LK.getAsset('target', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		//{2B} // Relative to container
		y: TARGET_Y + 40,
		//{1W} // Move inner target further back as well
		width: LANE_WIDTH - 30,
		height: TARGET_HEIGHT - 20
	});
	laneContainer.addChild(innerTarget);
	// (removed: misses counter above target, now shown on the target itself)
	// Add a misses counter directly ON the target (replaces label text with misses count)
	var targetOnText = new Text2('0', {
		size: 54,
		fill: 0x3399FF // Blue (not black)
	});
	targetOnText.anchor.set(0.5, 0.5);
	targetOnText.x = 0; // Relative to container
	targetOnText.y = TARGET_Y + 40;
	laneContainer.addChild(targetOnText);
	// Store this as the main misses counter for this target (for updating)
	targetMissTexts[i] = targetOnText;
	// Store both for later effects
	targets.push({
		outer: target,
		inner: innerTarget
	});
}
// Place people only outside the lanes, never over the road/lane area
// --- Randomized, non-overlapping, not-in-center people placement ---
peopleLeft = [];
peopleRight = [];
var NUM_PEOPLE_PER_EDGE = 0; // Start with no people
var PERSON_RADIUS = 90; // Half of body width, for spacing
var OUTER_X_OFFSET = 120; // How far outside the lane edge to place people
// Allow people to go all the way to the screen edge, not just near the lanes
var FAR_LEFT_X_MIN = 60;
var FAR_LEFT_X_MAX = getLaneX(0) - LANE_WIDTH / 2 - OUTER_X_OFFSET - 10;
var FAR_RIGHT_X_MIN = getLaneX(NUM_LANES - 1) + LANE_WIDTH / 2 + OUTER_X_OFFSET + 10;
var FAR_RIGHT_X_MAX = GAME_WIDTH - 60;
var Y_MIN = 200; // Don't go too high
var Y_MAX = TARGET_Y - 60; // Don't go too low
var CENTER_EXCLUSION_X = GAME_WIDTH / 2 - 320; // Exclude a wide center band
var CENTER_EXCLUSION_WIDTH = 640; // Center band width to avoid
var MAX_ATTEMPTS = 40; // Max tries to find a non-overlapping spot
function isFarEnough(x, y, arr) {
	for (var i = 0; i < arr.length; i++) {
		var dx = x - arr[i].x;
		var dy = y - arr[i].y;
		if (Math.sqrt(dx * dx + dy * dy) < PERSON_RADIUS * 2.1) return false;
	}
	return true;
}
function isNotCenter(x) {
	return !(x > CENTER_EXCLUSION_X && x < CENTER_EXCLUSION_X + CENTER_EXCLUSION_WIDTH);
}
// Check if position is not in drum area
function isNotDrumArea(x, y) {
	var drumRadius = 220;
	var leftDrumX = 200,
		leftDrumY = GAME_HEIGHT / 2;
	var rightDrumX = GAME_WIDTH - 200,
		rightDrumY = GAME_HEIGHT / 2;
	var distLeft = Math.sqrt((x - leftDrumX) * (x - leftDrumX) + (y - leftDrumY) * (y - leftDrumY));
	var distRight = Math.sqrt((x - rightDrumX) * (x - rightDrumX) + (y - rightDrumY) * (y - rightDrumY));
	return distLeft > drumRadius && distRight > drumRadius;
}
// Update popularity after recreating people
updatePopularity();
// Update initial popularity
updatePopularity();
// --- Song Data (Random Infinite Notes) ---
// Each note: {lane: 0-3, time: tick when note should reach target}
// We'll generate notes on the fly, at random lanes and random intervals
var bpm = 60;
var ticksPerBeat = 60 * 60 / bpm; // 60fps
var NOTE_TRAVEL_TICKS = 180; // 3 seconds at 60fps
// Infinite random note generator state
var nextNoteTick = 60; // When the next note should appear (in songTicks)
function getRandomLane() {
	return Math.floor(Math.random() * NUM_LANES);
}
function getRandomInterval() {
	// In extreme mode, spawn notes extremely frequently (interval is 0.12x to 0.35x of ticksPerBeat)
	if (typeof extremeMode !== "undefined" && extremeMode) {
		return Math.floor(ticksPerBeat * (0.12 + Math.random() * 0.23));
	}
	// In hard mode, spawn notes more frequently (interval is 0.3x to 1.0x of ticksPerBeat)
	if (typeof hardMode !== "undefined" && hardMode) {
		return Math.floor(ticksPerBeat * (0.3 + Math.random() * 0.7));
	}
	// Random interval between notes: 0.5x to 1.5x of ticksPerBeat
	return Math.floor(ticksPerBeat * (0.5 + Math.random()));
}
// --- Helper Functions ---
function getLaneX(laneIdx) {
	if (typeof laneContainers !== "undefined" && laneContainers[laneIdx]) {
		return laneContainers[laneIdx].x;
	}
	return LANE_START_X + laneIdx * (LANE_WIDTH + LANE_SPACING);
}
// Start continuous random lane movement
function startLaneMovement() {
	for (var i = 0; i < laneContainers.length; i++) {
		moveLaneRandomly(laneContainers[i], i);
	}
}
// Move a single lane to a random position
function moveLaneRandomly(laneContainer, index) {
	if (!laneContainer || songEnded) return;
	// Random offset from base position (-80 to +80 pixels)
	var randomOffset = (Math.random() - 0.5) * 160;
	var targetX = laneContainer.baseX + randomOffset;
	// Random duration (3-5 seconds)
	var duration = 3000 + Math.random() * 2000;
	tween(laneContainer, {
		x: targetX
	}, {
		duration: duration,
		easing: tween.easeInOut,
		onFinish: function onFinish() {
			// Continue moving after reaching target
			moveLaneRandomly(laneContainer, index);
		}
	});
}
// --- Game Logic ---
// Start song/music
function startSong() {
	if (songStarted) return;
	songStarted = true;
	LK.playMusic('song1');
	songTicks = 0;
	noteIndex = 0;
	score = 0;
	combo = 0;
	maxCombo = 0;
	misses = 0;
	songEnded = false;
	scoreTxt.setText('0');
	comboTxt.setText('');
	highScore = getHighScore();
	highScoreTxt.setText('High Score: ' + highScore);
	if (typeof bottomHighScoreTxt !== "undefined") {
		bottomHighScoreTxt.setText('High Score: ' + highScore);
	}
	notes.length = 0;
	// Reset per-target misses counters (on the target itself)
	if (typeof targets !== "undefined" && typeof targetMissTexts !== "undefined") {
		for (var i = 0; i < targetMissTexts.length; i++) {
			if (targetMissTexts[i]) {
				targetMissTexts[i].setText('0');
				targetMissTexts[i].setStyle({
					fill: 0x3399FF
				});
			}
			if (targets[i]) targets[i].missCount = 0;
		}
	}
	// Reset nextNoteTick and noteSpeedMultiplier to ensure smooth start
	nextNoteTick = 60;
	// Reset lane color flash state
	laneColorFlashActive = false;
	laneColorFlashStartTime = 0;
	laneColorFlashTriggered = false;
	// Reset drum state
	drumsActive = true;
	drumNotes.length = 0;
	if (leftDrum) {
		leftDrum.destroy();
		leftDrum = null;
	}
	if (rightDrum) {
		rightDrum.destroy();
		rightDrum = null;
	}
	// Remove peopleLeft from game
	if (typeof peopleLeft !== "undefined") {
		for (var i = 0; i < peopleLeft.length; i++) {
			if (peopleLeft[i] && typeof peopleLeft[i].destroy === "function") {
				peopleLeft[i].destroy();
			}
		}
		peopleLeft.length = 0;
	}
	// Remove peopleRight from game
	if (typeof peopleRight !== "undefined") {
		for (var i = 0; i < peopleRight.length; i++) {
			if (peopleRight[i] && typeof peopleRight[i].destroy === "function") {
				peopleRight[i].destroy();
			}
		}
		peopleRight.length = 0;
	}
	// Re-create peopleLeft and peopleRight, but keep them away from drum asset positions
	peopleLeft = [];
	peopleRight = [];
	currentPeoplePerSide = 0; // Reset to 0 people per side
	lastScoreMilestone = 0; // Reset score milestone
	var NUM_PEOPLE_PER_EDGE = 0; // Start with no people
	var PERSON_RADIUS = 90;
	var OUTER_X_OFFSET = 120;
	var FAR_LEFT_X_MIN = 60;
	var FAR_LEFT_X_MAX = getLaneX(0) - LANE_WIDTH / 2 - OUTER_X_OFFSET - 10;
	var FAR_RIGHT_X_MIN = getLaneX(NUM_LANES - 1) + LANE_WIDTH / 2 + OUTER_X_OFFSET + 10;
	var FAR_RIGHT_X_MAX = GAME_WIDTH - 60;
	var Y_MIN = 200;
	var Y_MAX = TARGET_Y - 60;
	var CENTER_EXCLUSION_X = GAME_WIDTH / 2 - 320;
	var CENTER_EXCLUSION_WIDTH = 640;
	var MAX_ATTEMPTS = 40;
	function isFarEnough(x, y, arr) {
		for (var i = 0; i < arr.length; i++) {
			var dx = x - arr[i].x;
			var dy = y - arr[i].y;
			if (Math.sqrt(dx * dx + dy * dy) < PERSON_RADIUS * 2.1) return false;
		}
		return true;
	}
	function isNotCenter(x) {
		return !(x > CENTER_EXCLUSION_X && x < CENTER_EXCLUSION_X + CENTER_EXCLUSION_WIDTH);
	}
	// No people are created at the start
	// Create left drum after people to ensure it appears in front
	leftDrum = LK.getAsset('drumV2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 200,
		y: GAME_HEIGHT / 2
	});
	game.addChild(leftDrum);
	// Create right drum after people to ensure it appears in front
	rightDrum = LK.getAsset('drumV2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: GAME_WIDTH - 200,
		y: GAME_HEIGHT / 2
	});
	game.addChild(rightDrum);
	// Drums will be created after people to ensure they appear in front
	// Set initial next drum note time based on mode: easy=10s, hard=5s, extreme=3s
	if (typeof extremeMode !== "undefined" && extremeMode) {
		// 3 seconds interval (180 ticks)
		nextDrumNoteTime = songTicks + 180;
	} else if (typeof hardMode !== "undefined" && hardMode) {
		// 5 seconds interval (300 ticks)
		nextDrumNoteTime = songTicks + 300;
	} else {
		// Easy mode or default: 10 seconds interval (600 ticks)
		nextDrumNoteTime = songTicks + 600;
	}
	// Start lane movement animations
	startLaneMovement();
	if (typeof extremeMode !== "undefined" && extremeMode) {
		noteSpeedMultiplier = 1.5; // Slower than before for extreme mode (spawn rate unchanged)
		// Remove any previous mode labels
		if (typeof hardModeLabel !== "undefined" && hardModeLabel && hardModeLabel.parent) {
			hardModeLabel.destroy();
		}
		if (typeof extremeModeLabel !== "undefined" && extremeModeLabel && extremeModeLabel.parent) {
			extremeModeLabel.destroy();
		}
		extremeModeLabel = new Text2('EXTREME MODE', {
			size: 80,
			fill: 0xFF00FF,
			font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
		});
		extremeModeLabel.anchor.set(0.5, 0);
		extremeModeLabel.x = GAME_WIDTH / 2;
		extremeModeLabel.y = 40;
		LK.gui.top.addChild(extremeModeLabel);
	} else if (typeof hardMode !== "undefined" && hardMode) {
		noteSpeedMultiplier = 1.7; // Reduced speed for hard mode
		// Show Hard Mode label in gameplay
		if (typeof hardModeLabel !== "undefined" && hardModeLabel && hardModeLabel.parent) {
			hardModeLabel.destroy();
		}
		if (typeof extremeModeLabel !== "undefined" && extremeModeLabel && extremeModeLabel.parent) {
			extremeModeLabel.destroy();
		}
		hardModeLabel = new Text2('HARD MODE', {
			size: 80,
			fill: 0xFF2222,
			font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
		});
		hardModeLabel.anchor.set(0.5, 0);
		hardModeLabel.x = GAME_WIDTH / 2;
		hardModeLabel.y = 40;
		LK.gui.top.addChild(hardModeLabel);
	} else if (typeof easyMode !== "undefined" && easyMode) {
		noteSpeedMultiplier = 1.0;
		// Show Easy Mode label in gameplay
		if (typeof hardModeLabel !== "undefined" && hardModeLabel && hardModeLabel.parent) {
			hardModeLabel.destroy();
		}
		if (typeof extremeModeLabel !== "undefined" && extremeModeLabel && extremeModeLabel.parent) {
			extremeModeLabel.destroy();
		}
		if (typeof easyModeLabel !== "undefined" && easyModeLabel && easyModeLabel.parent) {
			easyModeLabel.destroy();
		}
		easyModeLabel = new Text2('EASY MODE', {
			size: 80,
			fill: 0x44FF44,
			font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
		});
		easyModeLabel.anchor.set(0.5, 0);
		easyModeLabel.x = GAME_WIDTH / 2;
		easyModeLabel.y = 40;
		LK.gui.top.addChild(easyModeLabel);
	} else {
		noteSpeedMultiplier = 1.0;
		if (typeof hardModeLabel !== "undefined" && hardModeLabel && hardModeLabel.parent) {
			hardModeLabel.destroy();
		}
		if (typeof extremeModeLabel !== "undefined" && extremeModeLabel && extremeModeLabel.parent) {
			extremeModeLabel.destroy();
		}
	}
}
// End song/game
function endSong(win) {
	if (songEnded) return;
	songEnded = true;
	LK.stopMusic();
	// No win or game over, just stop music and mark as ended
}
// --- Input Handling ---
game.down = function (x, y, obj) {
	if (menuActive) return; // Prevent gameplay input until menu is dismissed
	// Only allow input if song is running
	if (!songStarted || songEnded) return;
	// Check drum hits first if drums are active
	if (drumsActive) {
		// Check left drum
		if (leftDrum) {
			var leftDrumLeft = leftDrum.x - 150;
			var leftDrumRight = leftDrum.x + 150;
			var leftDrumTop = leftDrum.y - 150;
			var leftDrumBottom = leftDrum.y + 150;
			if (x >= leftDrumLeft && x <= leftDrumRight && y >= leftDrumTop && y <= leftDrumBottom) {
				// Hit left drum - check for drum notes
				for (var d = drumNotes.length - 1; d >= 0; d--) {
					var drumNote = drumNotes[d];
					if (!drumNote.hit && drumNote.isLeft) {
						drumNote.onHit();
						score += 200;
						scoreTxt.setText(score + '');
						// Update high score
						if (score > highScore) {
							highScore = score;
							setHighScore(highScore);
							highScoreTxt.setText('High Score: ' + highScore);
							if (typeof bottomHighScoreTxt !== "undefined") {
								bottomHighScoreTxt.setText('High Score: ' + highScore);
							}
						}
						LK.getSound('davul').play();
						LK.getSound('tap').play();
						// Flash drum
						LK.effects.flashObject(leftDrum, 0xFFD700, 200);
						// Add drum hit animation
						tween.stop(leftDrum, {
							scaleX: true,
							scaleY: true
						});
						leftDrum.scaleX = 1;
						leftDrum.scaleY = 1;
						tween(leftDrum, {
							scaleX: 1.2,
							scaleY: 1.2
						}, {
							duration: 100,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								tween(leftDrum, {
									scaleX: 1,
									scaleY: 1
								}, {
									duration: 100,
									easing: tween.easeIn
								});
							}
						});
						// Add strong screen shake for drum hit
						if (typeof game !== "undefined" && typeof tween !== "undefined") {
							if (!game._isShaking) {
								game._isShaking = true;
								var originalGameX = game.x || 0;
								var originalGameY = game.y || 0;
								var shakeAmount = 200; // Always use consistent shake amount for drums
								var shakeDuration = 300;
								tween(game, {
									x: originalGameX + (Math.random() - 0.5) * shakeAmount,
									y: originalGameY + (Math.random() - 0.5) * shakeAmount
								}, {
									duration: shakeDuration,
									onFinish: function onFinish() {
										tween(game, {
											x: originalGameX,
											y: originalGameY
										}, {
											duration: shakeDuration,
											onFinish: function onFinish() {
												game._isShaking = false;
											}
										});
									}
								});
							}
						}
						return;
					}
				}
			}
		}
		// Check right drum
		if (rightDrum) {
			var rightDrumLeft = rightDrum.x - 150;
			var rightDrumRight = rightDrum.x + 150;
			var rightDrumTop = rightDrum.y - 150;
			var rightDrumBottom = rightDrum.y + 150;
			if (x >= rightDrumLeft && x <= rightDrumRight && y >= rightDrumTop && y <= rightDrumBottom) {
				// Hit right drum - check for drum notes
				for (var d = drumNotes.length - 1; d >= 0; d--) {
					var drumNote = drumNotes[d];
					if (!drumNote.hit && !drumNote.isLeft) {
						drumNote.onHit();
						score += 200;
						scoreTxt.setText(score + '');
						// Update high score
						if (score > highScore) {
							highScore = score;
							setHighScore(highScore);
							highScoreTxt.setText('High Score: ' + highScore);
							if (typeof bottomHighScoreTxt !== "undefined") {
								bottomHighScoreTxt.setText('High Score: ' + highScore);
							}
						}
						LK.getSound('davul').play();
						LK.getSound('tap').play();
						// Flash drum
						LK.effects.flashObject(rightDrum, 0xFFD700, 200);
						// Add drum hit animation
						tween.stop(rightDrum, {
							scaleX: true,
							scaleY: true
						});
						rightDrum.scaleX = 1;
						rightDrum.scaleY = 1;
						tween(rightDrum, {
							scaleX: 1.2,
							scaleY: 1.2
						}, {
							duration: 100,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								tween(rightDrum, {
									scaleX: 1,
									scaleY: 1
								}, {
									duration: 100,
									easing: tween.easeIn
								});
							}
						});
						// Add strong screen shake for drum hit
						if (typeof game !== "undefined" && typeof tween !== "undefined") {
							if (!game._isShaking) {
								game._isShaking = true;
								var originalGameX = game.x || 0;
								var originalGameY = game.y || 0;
								var shakeAmount = 200; // Always use consistent shake amount for drums
								var shakeDuration = 300;
								tween(game, {
									x: originalGameX + (Math.random() - 0.5) * shakeAmount,
									y: originalGameY + (Math.random() - 0.5) * shakeAmount
								}, {
									duration: shakeDuration,
									onFinish: function onFinish() {
										tween(game, {
											x: originalGameX,
											y: originalGameY
										}, {
											duration: shakeDuration,
											onFinish: function onFinish() {
												game._isShaking = false;
											}
										});
									}
								});
							}
						}
						return;
					}
				}
			}
		}
	}
	// Pause people movement for 2 seconds (120 ticks) after a note is hit
	if (typeof game._peopleMovePausedUntil === "undefined") game._peopleMovePausedUntil = 0;
	game._peopleMovePausedUntil = songTicks + 120;
	// Check if tap is on any note (from topmost to bottom)
	var hit = false;
	var _loop = function _loop() {
			note = notes[i];
			if (note.hit || note.missed) return 0; // continue
			// Get note bounds
			noteLeft = note.x - NOTE_WIDTH / 2;
			noteRight = note.x + NOTE_WIDTH / 2;
			noteTop = note.y - NOTE_HEIGHT / 2;
			noteBottom = note.y + NOTE_HEIGHT / 2;
			if (x >= noteLeft && x <= noteRight && y >= noteTop && y <= noteBottom) {
				// Hit!
				note.onHit();
				hit = true;
				score += 100;
				combo += 1;
				if (combo > maxCombo) maxCombo = combo;
				scoreTxt.setText(score + '');
				comboTxt.setText(combo > 1 ? combo + ' Combo!' : '');
				// High score logic
				if (score > highScore) {
					highScore = score;
					setHighScore(highScore);
					highScoreTxt.setText('High Score: ' + highScore);
					if (typeof bottomHighScoreTxt !== "undefined") {
						bottomHighScoreTxt.setText('High Score: ' + highScore);
					}
				}
				LK.getSound('tap').play();
				// Make a random subset of people jump when any note is hit!
				// Every 10 combo, make all people jump and apply a stronger shake
				if (typeof peopleLeft !== "undefined" && typeof peopleRight !== "undefined") {
					if (combo > 0 && combo % 50 === 0) {
						// --- MASSIVE SHAKE for every 50 combo ---
						// All people jump!
						for (var iAll = 0; iAll < peopleLeft.length; iAll++) {
							if (peopleLeft[iAll]) peopleLeft[iAll].jump();
						}
						for (var iAll = 0; iAll < peopleRight.length; iAll++) {
							if (peopleRight[iAll]) peopleRight[iAll].jump();
						}
						// Massive shake: override game.x/y with a huge shake
						if (typeof game !== "undefined" && typeof tween !== "undefined") {
							if (!game._isShaking) {
								game._isShaking = true;
								var originalGameX = game.x || 0;
								var originalGameY = game.y || 0;
								var shakeAmount = 420; // extremely strong shake
								var shakeDuration = 420;
								tween(game, {
									x: originalGameX + (Math.random() - 0.5) * shakeAmount,
									y: originalGameY + (Math.random() - 0.5) * shakeAmount
								}, {
									duration: shakeDuration,
									onFinish: function onFinish() {
										tween(game, {
											x: originalGameX,
											y: originalGameY
										}, {
											duration: shakeDuration,
											onFinish: function onFinish() {
												game._isShaking = false;
											}
										});
									}
								});
							}
						}
					} else if (combo > 0 && combo % 10 === 0) {
						// All people jump!
						for (var iAll = 0; iAll < peopleLeft.length; iAll++) {
							if (peopleLeft[iAll]) peopleLeft[iAll].jump();
						}
						for (var iAll = 0; iAll < peopleRight.length; iAll++) {
							if (peopleRight[iAll]) peopleRight[iAll].jump();
						}
						// Stronger shake: override game.x/y with a bigger shake
						if (typeof game !== "undefined" && typeof tween !== "undefined") {
							if (!game._isShaking) {
								game._isShaking = true;
								var originalGameX = game.x || 0;
								var originalGameY = game.y || 0;
								var shakeAmount = 60; // much stronger shake
								var shakeDuration = 120;
								tween(game, {
									x: originalGameX + (Math.random() - 0.5) * shakeAmount,
									y: originalGameY + (Math.random() - 0.5) * shakeAmount
								}, {
									duration: shakeDuration,
									onFinish: function onFinish() {
										tween(game, {
											x: originalGameX,
											y: originalGameY
										}, {
											duration: shakeDuration,
											onFinish: function onFinish() {
												game._isShaking = false;
											}
										});
									}
								});
							}
						}
					} else {
						// Helper to get unique random indices
						var getRandomIndices = function getRandomIndices(arrLen, count) {
							var indices = [];
							var used = [];
							while (indices.length < count && indices.length < arrLen) {
								var idx = Math.floor(Math.random() * arrLen);
								if (!used[idx]) {
									indices.push(idx);
									used[idx] = true;
								}
							}
							return indices;
						};
						// How many people to jump per side? 1-3 random per side
						leftJumpCount = 1 + Math.floor(Math.random() * 3);
						rightJumpCount = 1 + Math.floor(Math.random() * 3);
						leftIndices = getRandomIndices(peopleLeft.length, leftJumpCount);
						rightIndices = getRandomIndices(peopleRight.length, rightJumpCount);
						for (j = 0; j < leftIndices.length; j++) {
							idx = leftIndices[j];
							if (peopleLeft[idx]) peopleLeft[idx].jump();
						}
						for (j = 0; j < rightIndices.length; j++) {
							idx = rightIndices[j];
							if (peopleRight[idx]) peopleRight[idx].jump();
						}
					}
				}
				// Show floating feedback text based on combo
				feedbackText = '';
				if (combo >= 30) {
					feedbackText = 'PERFECT!';
				} else if (combo >= 15) {
					feedbackText = 'GREAT!';
				} else if (combo >= 5) {
					feedbackText = 'GOOD!';
				}
				if (feedbackText) {
					fbTxt = new Text2(feedbackText, {
						size: 120,
						fill: 0xFFD700,
						font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
					});
					fbTxt.anchor.set(0.5, 0.5);
					fbTxt.x = GAME_WIDTH / 2;
					fbTxt.y = GAME_HEIGHT / 2 - 200;
					fbTxt.alpha = 1;
					game.addChild(fbTxt);
					tween(fbTxt, {
						y: fbTxt.y - 120,
						alpha: 0
					}, {
						duration: 700,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							fbTxt.destroy();
						}
					});
				}
				return 1; // break
			}
		},
		note,
		noteLeft,
		noteRight,
		noteTop,
		noteBottom,
		leftJumpCount,
		rightJumpCount,
		leftIndices,
		rightIndices,
		j,
		idx,
		j,
		idx,
		feedbackText,
		fbTxt,
		_ret;
	for (var i = notes.length - 1; i >= 0; i--) {
		_ret = _loop();
		if (_ret === 0) continue;
		if (_ret === 1) break;
	}
	if (!hit) {
		// Missed tap (no note hit)
		combo = 0;
		comboTxt.setText('');
		// No misses for tap misses, no flash
	}
};
// --- Main Game Loop ---
game.update = function () {
	if (!songStarted || songEnded) return;
	songTicks += 1;
	// Create drums at game start (handled in startSong)
	// Spawn drum notes
	if (drumsActive && songTicks >= nextDrumNoteTime) {
		var drumNote = new DrumNote();
		drumNote.spawnTime = songTicks;
		// Randomly choose left or right drum
		drumNote.isLeft = Math.random() < 0.5;
		if (drumNote.isLeft) {
			drumNote.x = leftDrum.x;
			drumNote.y = leftDrum.y;
		} else {
			drumNote.x = rightDrum.x;
			drumNote.y = rightDrum.y;
		}
		drumNotes.push(drumNote);
		game.addChild(drumNote);
		// Schedule next drum note based on mode: easy=10s, hard=5s, extreme=3s
		if (typeof extremeMode !== "undefined" && extremeMode) {
			// 3 seconds interval (180 ticks)
			nextDrumNoteTime = songTicks + 180;
		} else if (typeof hardMode !== "undefined" && hardMode) {
			// 5 seconds interval (300 ticks)
			nextDrumNoteTime = songTicks + 300;
		} else {
			// Easy mode or default: 10 seconds interval (600 ticks)
			nextDrumNoteTime = songTicks + 600;
		}
	}
	// Update drum notes
	for (var d = drumNotes.length - 1; d >= 0; d--) {
		var drumNote = drumNotes[d];
		drumNote.update();
		if (drumNote.destroyed) {
			drumNotes.splice(d, 1);
		}
	}
	// Check if all people are jumping and change lane colors
	if (typeof peopleLeft !== "undefined" && typeof peopleRight !== "undefined") {
		var allJumping = true;
		// Check if all left people are jumping
		for (var i = 0; i < peopleLeft.length; i++) {
			if (peopleLeft[i] && !peopleLeft[i].isJumping) {
				allJumping = false;
				break;
			}
		}
		// Check if all right people are jumping
		if (allJumping) {
			for (var i = 0; i < peopleRight.length; i++) {
				if (peopleRight[i] && !peopleRight[i].isJumping) {
					allJumping = false;
					break;
				}
			}
		}
		// If all people are jumping, change lane colors randomly
		if (allJumping && peopleLeft.length > 0 && peopleRight.length > 0) {
			if (!game._lastAllJumping) {
				// This is the moment when all started jumping
				var colors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFA500, 0xFF1493, 0x32CD32, 0x8A2BE2];
				for (var l = 0; l < lanes.length; l++) {
					if (lanes[l]) {
						var randomColor = colors[Math.floor(Math.random() * colors.length)];
						lanes[l].tint = randomColor;
					}
				}
			}
			game._lastAllJumping = true;
		} else {
			game._lastAllJumping = false;
		}
	}
	// Gradually increase noteSpeedMultiplier (very slow ramp, e.g. +0.0002 per tick)
	// In normal mode, do NOT increase speed faster after 5000 points
	if (noteSpeedMultiplier < 2.0) {
		noteSpeedMultiplier += 0.0002;
		if (noteSpeedMultiplier > 2.0) noteSpeedMultiplier = 2.0;
	}
	// Spawn notes as needed (random, infinite)
	// After 5000 points, do not increase note spawn count; only speed increases
	var notesToSpawn = 1;
	// No change to notesToSpawn after 5000 points
	while (songTicks >= nextNoteTick - NOTE_TRAVEL_TICKS) {
		for (var spawnIdx = 0; spawnIdx < notesToSpawn; spawnIdx++) {
			var lane = getRandomLane();
			var noteTime = nextNoteTick;
			var note = new Note();
			note.setLane(lane);
			// Spawn note at current lane container position
			note.x = laneContainers[lane].x;
			note.y = -NOTE_HEIGHT / 2;
			note.speed = (TARGET_Y + NOTE_HEIGHT / 2) / NOTE_TRAVEL_TICKS * noteSpeedMultiplier;
			note.time = noteTime;
			note.spawned = true;
			// Store reference to lane container so note can follow it
			note.laneContainer = laneContainers[lane];
			notes.push(note);
			game.addChild(note);
		}
		// Schedule next note
		nextNoteTick += getRandomInterval();
	}
	// Check if score reached 5000 for lane color flashing
	if (score >= 5000 && !laneColorFlashTriggered) {
		laneColorFlashTriggered = true;
		laneColorFlashActive = true;
		laneColorFlashStartTime = songTicks;
	}
	// Handle rapid lane color changes
	if (laneColorFlashActive) {
		var flashDuration = 600; // 10 seconds at 60fps
		var elapsed = songTicks - laneColorFlashStartTime;
		if (elapsed < flashDuration) {
			// Change colors very rapidly (every 3 frames = 20 times per second)
			if (songTicks % 3 === 0) {
				var colors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFA500, 0xFF1493, 0x32CD32, 0x8A2BE2, 0xFFD700, 0x4B0082, 0x7FFF00, 0xDC143C, 0x00CED1];
				for (var l = 0; l < lanes.length; l++) {
					if (lanes[l]) {
						var randomColor = colors[Math.floor(Math.random() * colors.length)];
						tween(lanes[l], {
							tint: randomColor
						}, {
							duration: 50,
							easing: tween.linear
						});
					}
				}
			}
		} else {
			// Reset to original color after 10 seconds
			laneColorFlashActive = false;
			for (var l = 0; l < lanes.length; l++) {
				if (lanes[l]) {
					tween(lanes[l], {
						tint: 0x222222
					}, {
						duration: 300,
						easing: tween.easeOut
					});
				}
			}
		}
	}
	// Add people every 500 points, up to 5 per side (10 total)
	if (score >= lastScoreMilestone + 500 && currentPeoplePerSide < 5) {
		lastScoreMilestone = Math.floor(score / 500) * 500;
		currentPeoplePerSide++;
		// Add one person to left side
		var leftPerson = new People();
		var attempts = 0;
		var px, py;
		do {
			py = Y_MIN + Math.random() * (Y_MAX - Y_MIN);
			px = FAR_LEFT_X_MIN + Math.random() * (FAR_LEFT_X_MAX - FAR_LEFT_X_MIN);
			attempts++;
		} while ((!isFarEnough(px, py, peopleLeft) || !isNotCenter(px) || !isNotDrumArea(px, py)) && attempts < MAX_ATTEMPTS);
		leftPerson.x = px;
		leftPerson.y = py;
		game.addChild(leftPerson);
		peopleLeft.push(leftPerson);
		// Add one person to right side
		var rightPerson = new People();
		attempts = 0;
		do {
			py = Y_MIN + Math.random() * (Y_MAX - Y_MIN);
			px = FAR_RIGHT_X_MIN + Math.random() * (FAR_RIGHT_X_MAX - FAR_RIGHT_X_MIN);
			attempts++;
		} while ((!isFarEnough(px, py, peopleRight) || !isNotCenter(px) || !isNotDrumArea(px, py)) && attempts < MAX_ATTEMPTS);
		rightPerson.x = px;
		rightPerson.y = py;
		game.addChild(rightPerson);
		peopleRight.push(rightPerson);
		// Update popularity when new people are added
		updatePopularity();
	}
	// Update notes
	for (var i = notes.length - 1; i >= 0; i--) {
		var note = notes[i];
		note.update();
		// If note reached target zone and not hit, mark as missed
		if (!note.hit && !note.missed && note.y >= TARGET_Y + TARGET_HEIGHT / 2) {
			note.onMiss();
			combo = 0;
			misses += 1;
			comboTxt.setText('');
			// Increment and show per-target misses in white above each target
			if (!targets[note.lane].missCount) targets[note.lane].missCount = 0;
			targets[note.lane].missCount += 1;
			if (targetMissTexts && targetMissTexts[note.lane]) {
				targetMissTexts[note.lane].setText(targets[note.lane].missCount + '');
				targetMissTexts[note.lane].setStyle({
					fill: 0x3399FF
				});
			}
			// Decrease popularity by 2% and remove one person when a note is missed
			// Remove one person randomly from either left or right side
			var removedPerson = false;
			if (Math.random() < 0.5 && peopleLeft.length > 0) {
				// Remove from left side
				var personToRemove = peopleLeft.pop();
				if (personToRemove && personToRemove.destroy) {
					personToRemove.destroy();
					removedPerson = true;
				}
			} else if (peopleRight.length > 0) {
				// Remove from right side
				var personToRemove = peopleRight.pop();
				if (personToRemove && personToRemove.destroy) {
					personToRemove.destroy();
					removedPerson = true;
				}
			}
			// Update popularity after removing person
			if (removedPerson) {
				updatePopularity();
			}
			LK.getSound('miss').play({
				fade: {
					start: 1,
					end: 0,
					duration: 1000
				}
			});
			LK.effects.flashObject(targets[note.lane].outer, 0xff0000, 200);
			LK.effects.flashObject(targets[note.lane].inner, 0xff6666, 200);
			if (misses >= maxMisses) {
				// No game over, just keep going
			}
			// Check if any target's miss count exceeds 10, trigger game over
			for (var t = 0; t < targets.length; t++) {
				if (targets[t].missCount && targets[t].missCount > 10) {
					LK.showGameOver();
					return;
				}
			}
		}
		// Remove destroyed notes
		if (note.destroyed) {
			notes.splice(i, 1);
		}
	}
	// --- Move people to new random positions every 2 seconds ---
	if (typeof game._lastPeopleMoveTick === "undefined") game._lastPeopleMoveTick = 0;
	if (typeof game._peopleMovePausedUntil === "undefined") game._peopleMovePausedUntil = 0;
	// Only move people if not in the 2s pause after a note hit
	if (songTicks - game._lastPeopleMoveTick > 120 && songTicks >= game._peopleMovePausedUntil) {
		// Helper to move a person to a new random position (non-overlapping, not center)
		var movePerson = function movePerson(person, arr, isLeft) {
			var attempts = 0;
			var px, py;
			do {
				py = Y_MIN + Math.random() * (Y_MAX - Y_MIN);
				if (isLeft) {
					// Move anywhere in the left empty area
					px = FAR_LEFT_X_MIN + Math.random() * (FAR_LEFT_X_MAX - FAR_LEFT_X_MIN);
				} else {
					// Move anywhere in the right empty area
					px = FAR_RIGHT_X_MIN + Math.random() * (FAR_RIGHT_X_MAX - FAR_RIGHT_X_MIN);
				}
				attempts++;
			} while ((!isFarEnough(px, py, arr) || !isNotCenter(px)) && attempts < MAX_ATTEMPTS);
			// Animate to new position (move very slowly, never teleport)
			tween(person, {
				x: px,
				y: py
			}, {
				duration: 3200,
				// much slower movement (3.2 seconds)
				easing: tween.easeInOut
			});
			person.baseY = py;
		}; // Move left people
		// every 2 seconds at 60fps
		game._lastPeopleMoveTick = songTicks;
		for (var i = 0; i < peopleLeft.length; i++) {
			movePerson(peopleLeft[i], peopleLeft, true);
		}
		// Move right people
		for (var i = 0; i < peopleRight.length; i++) {
			movePerson(peopleRight[i], peopleRight, false);
		}
	}
	// No win condition, keep game running
};
// --- Start Menu Overlay ---
var startMenuOverlay = new Container();
var overlayBg = LK.getAsset('lane', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: GAME_WIDTH / 2,
	y: GAME_HEIGHT / 2,
	width: GAME_WIDTH,
	height: GAME_HEIGHT,
	color: 0x000000
});
overlayBg.alpha = 0.85;
startMenuOverlay.addChild(overlayBg);
var titleText = new Text2('BEAT TAPPER', {
	size: 120,
	fill: 0xFFD700,
	font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = GAME_WIDTH / 2;
titleText.y = GAME_HEIGHT / 2 - 400;
startMenuOverlay.addChild(titleText);
var tapToStartText = new Text2('Tap to Start', {
	size: 90,
	fill: 0xFFFFFF
});
tapToStartText.anchor.set(0.5, 0.5);
tapToStartText.x = GAME_WIDTH / 2;
// Move even higher above instructions (was -60, now -120 for more space above instructions)
tapToStartText.y = GAME_HEIGHT / 2 - 120;
// Create a box behind the text
var tapBoxPaddingX = 60;
var tapBoxPaddingY = 30;
var tapBox = LK.getAsset('lane', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: tapToStartText.x,
	y: tapToStartText.y,
	width: tapToStartText.width + tapBoxPaddingX,
	height: tapToStartText.height + tapBoxPaddingY,
	color: 0xFFFFFF
});
tapBox.alpha = 0.18;
startMenuOverlay.addChild(tapBox);
startMenuOverlay.addChild(tapToStartText);
var instructionsText = new Text2("How to Play:\n\n" + "• Tap the falling notes when they reach the targets.\n" + "• Don't let too many notes pass the targets!\n" + "• Each lane shows your misses. If any lane gets more than 10 misses, it's game over.\n" + "• Try to get the highest combo and score!", {
	size: 44,
	fill: 0xFFFFFF,
	align: "center"
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = GAME_WIDTH / 2;
instructionsText.y = GAME_HEIGHT / 2 + 120;
startMenuOverlay.addChild(instructionsText);
var highScoreMenuText = new Text2('High Score: ' + getHighScore(), {
	size: 70,
	fill: 0xFFD700,
	align: "center"
});
highScoreMenuText.anchor.set(0.5, 0.5);
highScoreMenuText.x = GAME_WIDTH / 2;
highScoreMenuText.y = GAME_HEIGHT / 2 + 320;
startMenuOverlay.addChild(highScoreMenuText);
// Add drum instructions at the very bottom of the menu overlay
var drumInstructionsText = new Text2("At the start of the game, two drums (left and right) will appear.\n" + "Drum notes will randomly appear above the drums.\n" + "Tap the drum note within 5 seconds to score points!\n" + "If you don't tap the drum note in 5 seconds, you lose.", {
	size: 40,
	fill: 0xFFD700,
	align: "center"
});
drumInstructionsText.anchor.set(0.5, 1);
drumInstructionsText.x = GAME_WIDTH / 2;
drumInstructionsText.y = GAME_HEIGHT - 60;
startMenuOverlay.addChild(drumInstructionsText);
// --- Easy Mode Button ---
var easyModeBtn = new Text2('Easy Mode', {
	size: 80,
	fill: 0x44FF44,
	font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
easyModeBtn.anchor.set(0.5, 0.5);
easyModeBtn.x = GAME_WIDTH / 2;
easyModeBtn.y = GAME_HEIGHT / 2 + 480;
easyModeBtn.alpha = 0.92;
easyModeBtn._isEasyModeBtn = true;
startMenuOverlay.addChild(easyModeBtn);
// --- Hard Mode Button ---
var hardModeBtn = new Text2('Hard Mode', {
	size: 80,
	fill: 0xFF2222,
	font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
hardModeBtn.anchor.set(0.5, 0.5);
hardModeBtn.x = GAME_WIDTH / 2;
hardModeBtn.y = GAME_HEIGHT / 2 + 620;
hardModeBtn.alpha = 0.92;
hardModeBtn._isHardModeBtn = true;
startMenuOverlay.addChild(hardModeBtn);
// --- Extreme Mode Button ---
var extremeModeBtn = new Text2('Extreme Mode', {
	size: 80,
	fill: 0xFF00FF,
	font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
extremeModeBtn.anchor.set(0.5, 0.5);
extremeModeBtn.x = GAME_WIDTH / 2;
extremeModeBtn.y = GAME_HEIGHT / 2 + 760;
extremeModeBtn.alpha = 0.92;
extremeModeBtn._isExtremeModeBtn = true;
startMenuOverlay.addChild(extremeModeBtn);
game.addChild(startMenuOverlay);
var menuActive = true;
var hardMode = false;
var extremeMode = false;
var easyMode = true; // Default to easy mode
game.down = function (x, y, obj) {
	if (menuActive) {
		// Check if tap is on Easy Mode button
		var easyBtnLeft = easyModeBtn.x - easyModeBtn.width / 2;
		var easyBtnRight = easyModeBtn.x + easyModeBtn.width / 2;
		var easyBtnTop = easyModeBtn.y - easyModeBtn.height / 2;
		var easyBtnBottom = easyModeBtn.y + easyModeBtn.height / 2;
		if (x >= easyBtnLeft && x <= easyBtnRight && y >= easyBtnTop && y <= easyBtnBottom) {
			// Toggle easy mode ON and visually indicate
			easyMode = true;
			hardMode = false;
			extremeMode = false;
			easyModeBtn.setText('Easy Mode: ON');
			easyModeBtn.fill = 0x66FF66;
			easyModeBtn.alpha = 1;
			hardModeBtn.setText('Hard Mode');
			hardModeBtn.fill = 0xFF2222;
			hardModeBtn.alpha = 0.92;
			extremeModeBtn.setText('Extreme Mode');
			extremeModeBtn.fill = 0xFF00FF;
			extremeModeBtn.alpha = 0.92;
			// Update high score in menu overlay
			if (typeof highScoreMenuText !== "undefined") {
				highScoreMenuText.setText('High Score: ' + getHighScore());
			}
			// Optionally, flash or animate
			tween(easyModeBtn, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 120,
				yoyo: true,
				repeat: 1,
				onFinish: function onFinish() {
					easyModeBtn.scaleX = 1;
					easyModeBtn.scaleY = 1;
				}
			});
			return;
		}
		// Check if tap is on Hard Mode button
		var btnLeft = hardModeBtn.x - hardModeBtn.width / 2;
		var btnRight = hardModeBtn.x + hardModeBtn.width / 2;
		var btnTop = hardModeBtn.y - hardModeBtn.height / 2;
		var btnBottom = hardModeBtn.y + hardModeBtn.height / 2;
		if (x >= btnLeft && x <= btnRight && y >= btnTop && y <= btnBottom) {
			// Toggle hard mode ON and visually indicate
			hardMode = true;
			easyMode = false;
			extremeMode = false;
			hardModeBtn.setText('Hard Mode: ON');
			hardModeBtn.fill = 0xFF4444;
			hardModeBtn.alpha = 1;
			easyModeBtn.setText('Easy Mode');
			easyModeBtn.fill = 0x44FF44;
			easyModeBtn.alpha = 0.92;
			extremeModeBtn.setText('Extreme Mode');
			extremeModeBtn.fill = 0xFF00FF;
			extremeModeBtn.alpha = 0.92;
			// Update high score in menu overlay
			if (typeof highScoreMenuText !== "undefined") {
				highScoreMenuText.setText('High Score: ' + getHighScore());
			}
			// Optionally, flash or animate
			tween(hardModeBtn, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 120,
				yoyo: true,
				repeat: 1,
				onFinish: function onFinish() {
					hardModeBtn.scaleX = 1;
					hardModeBtn.scaleY = 1;
				}
			});
			return;
		}
		// Check if tap is on Extreme Mode button
		var ebtnLeft = extremeModeBtn.x - extremeModeBtn.width / 2;
		var ebtnRight = extremeModeBtn.x + extremeModeBtn.width / 2;
		var ebtnTop = extremeModeBtn.y - extremeModeBtn.height / 2;
		var ebtnBottom = extremeModeBtn.y + extremeModeBtn.height / 2;
		if (x >= ebtnLeft && x <= ebtnRight && y >= ebtnTop && y <= ebtnBottom) {
			// Toggle extreme mode ON and visually indicate
			extremeMode = true;
			hardMode = false;
			easyMode = false;
			extremeModeBtn.setText('Extreme Mode: ON');
			extremeModeBtn.fill = 0xFF66FF;
			extremeModeBtn.alpha = 1;
			hardModeBtn.setText('Hard Mode');
			hardModeBtn.fill = 0xFF2222;
			hardModeBtn.alpha = 0.92;
			easyModeBtn.setText('Easy Mode');
			easyModeBtn.fill = 0x44FF44;
			easyModeBtn.alpha = 0.92;
			// Update high score in menu overlay
			if (typeof highScoreMenuText !== "undefined") {
				highScoreMenuText.setText('High Score: ' + getHighScore());
			}
			// Optionally, flash or animate
			tween(extremeModeBtn, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 120,
				yoyo: true,
				repeat: 1,
				onFinish: function onFinish() {
					extremeModeBtn.scaleX = 1;
					extremeModeBtn.scaleY = 1;
				}
			});
			return;
		}
		menuActive = false;
		startMenuOverlay.destroy();
		startSong();
		// Restore original input handler for gameplay
		game.down = function (x, y, obj) {
			// Only allow input if song is running
			if (!songStarted || songEnded) return;
			// Check drum hits first if drums are active
			if (drumsActive) {
				// Check left drum
				if (leftDrum) {
					var leftDrumLeft = leftDrum.x - 150;
					var leftDrumRight = leftDrum.x + 150;
					var leftDrumTop = leftDrum.y - 150;
					var leftDrumBottom = leftDrum.y + 150;
					if (x >= leftDrumLeft && x <= leftDrumRight && y >= leftDrumTop && y <= leftDrumBottom) {
						// Hit left drum - check for drum notes
						for (var d = drumNotes.length - 1; d >= 0; d--) {
							var drumNote = drumNotes[d];
							if (!drumNote.hit && drumNote.isLeft) {
								drumNote.onHit();
								score += 200;
								scoreTxt.setText(score + '');
								// Update high score
								if (score > highScore) {
									highScore = score;
									setHighScore(highScore);
									highScoreTxt.setText('High Score: ' + highScore);
									if (typeof bottomHighScoreTxt !== "undefined") {
										bottomHighScoreTxt.setText('High Score: ' + highScore);
									}
								}
								LK.getSound('davul').play();
								LK.getSound('tap').play();
								// Flash drum
								LK.effects.flashObject(leftDrum, 0xFFD700, 200);
								// Add drum hit animation
								tween.stop(leftDrum, {
									scaleX: true,
									scaleY: true
								});
								leftDrum.scaleX = 1;
								leftDrum.scaleY = 1;
								tween(leftDrum, {
									scaleX: 1.2,
									scaleY: 1.2
								}, {
									duration: 100,
									easing: tween.easeOut,
									onFinish: function onFinish() {
										tween(leftDrum, {
											scaleX: 1,
											scaleY: 1
										}, {
											duration: 100,
											easing: tween.easeIn
										});
									}
								});
								// Add strong screen shake for drum hit
								if (typeof game !== "undefined" && typeof tween !== "undefined") {
									if (!game._isShaking) {
										game._isShaking = true;
										var originalGameX = game.x || 0;
										var originalGameY = game.y || 0;
										var shakeAmount = 200; // Always use consistent shake amount for drums
										var shakeDuration = 300;
										tween(game, {
											x: originalGameX + (Math.random() - 0.5) * shakeAmount,
											y: originalGameY + (Math.random() - 0.5) * shakeAmount
										}, {
											duration: shakeDuration,
											onFinish: function onFinish() {
												tween(game, {
													x: originalGameX,
													y: originalGameY
												}, {
													duration: shakeDuration,
													onFinish: function onFinish() {
														game._isShaking = false;
													}
												});
											}
										});
									}
								}
								return;
							}
						}
					}
				}
				// Check right drum
				if (rightDrum) {
					var rightDrumLeft = rightDrum.x - 150;
					var rightDrumRight = rightDrum.x + 150;
					var rightDrumTop = rightDrum.y - 150;
					var rightDrumBottom = rightDrum.y + 150;
					if (x >= rightDrumLeft && x <= rightDrumRight && y >= rightDrumTop && y <= rightDrumBottom) {
						// Hit right drum - check for drum notes
						for (var d = drumNotes.length - 1; d >= 0; d--) {
							var drumNote = drumNotes[d];
							if (!drumNote.hit && !drumNote.isLeft) {
								drumNote.onHit();
								score += 200;
								scoreTxt.setText(score + '');
								// Update high score
								if (score > highScore) {
									highScore = score;
									setHighScore(highScore);
									highScoreTxt.setText('High Score: ' + highScore);
									if (typeof bottomHighScoreTxt !== "undefined") {
										bottomHighScoreTxt.setText('High Score: ' + highScore);
									}
								}
								LK.getSound('davul').play();
								LK.getSound('tap').play();
								// Flash drum
								LK.effects.flashObject(rightDrum, 0xFFD700, 200);
								// Add drum hit animation
								tween.stop(rightDrum, {
									scaleX: true,
									scaleY: true
								});
								rightDrum.scaleX = 1;
								rightDrum.scaleY = 1;
								tween(rightDrum, {
									scaleX: 1.2,
									scaleY: 1.2
								}, {
									duration: 100,
									easing: tween.easeOut,
									onFinish: function onFinish() {
										tween(rightDrum, {
											scaleX: 1,
											scaleY: 1
										}, {
											duration: 100,
											easing: tween.easeIn
										});
									}
								});
								// Add strong screen shake for drum hit
								if (typeof game !== "undefined" && typeof tween !== "undefined") {
									if (!game._isShaking) {
										game._isShaking = true;
										var originalGameX = game.x || 0;
										var originalGameY = game.y || 0;
										var shakeAmount = 200; // Always use consistent shake amount for drums
										var shakeDuration = 300;
										tween(game, {
											x: originalGameX + (Math.random() - 0.5) * shakeAmount,
											y: originalGameY + (Math.random() - 0.5) * shakeAmount
										}, {
											duration: shakeDuration,
											onFinish: function onFinish() {
												tween(game, {
													x: originalGameX,
													y: originalGameY
												}, {
													duration: shakeDuration,
													onFinish: function onFinish() {
														game._isShaking = false;
													}
												});
											}
										});
									}
								}
								return;
							}
						}
					}
				}
			}
			// Pause people movement for 2 seconds (120 ticks) after a note is hit
			if (typeof game._peopleMovePausedUntil === "undefined") game._peopleMovePausedUntil = 0;
			game._peopleMovePausedUntil = songTicks + 120;
			// Check if tap is on any note (from topmost to bottom)
			var hit = false;
			var _loop = function _loop() {
					note = notes[i];
					if (note.hit || note.missed) return 0; // continue
					// Get note bounds
					noteLeft = note.x - NOTE_WIDTH / 2;
					noteRight = note.x + NOTE_WIDTH / 2;
					noteTop = note.y - NOTE_HEIGHT / 2;
					noteBottom = note.y + NOTE_HEIGHT / 2;
					if (x >= noteLeft && x <= noteRight && y >= noteTop && y <= noteBottom) {
						// Hit!
						note.onHit();
						hit = true;
						score += 100;
						combo += 1;
						if (combo > maxCombo) maxCombo = combo;
						scoreTxt.setText(score + '');
						comboTxt.setText(combo > 1 ? combo + ' Combo!' : '');
						// High score logic
						if (score > highScore) {
							highScore = score;
							setHighScore(highScore);
							highScoreTxt.setText('High Score: ' + highScore);
							if (typeof bottomHighScoreTxt !== "undefined") {
								bottomHighScoreTxt.setText('High Score: ' + highScore);
							}
						}
						LK.getSound('tap').play();
						// Make a random subset of people jump when any note is hit!
						// Every 10 combo, make all people jump and apply a stronger shake
						if (typeof peopleLeft !== "undefined" && typeof peopleRight !== "undefined") {
							if (combo > 0 && combo % 50 === 0) {
								// --- MASSIVE SHAKE for every 50 combo ---
								// All people jump!
								for (var iAll = 0; iAll < peopleLeft.length; iAll++) {
									if (peopleLeft[iAll]) peopleLeft[iAll].jump();
								}
								for (var iAll = 0; iAll < peopleRight.length; iAll++) {
									if (peopleRight[iAll]) peopleRight[iAll].jump();
								}
								// Massive shake: override game.x/y with a huge shake
								if (typeof game !== "undefined" && typeof tween !== "undefined") {
									if (!game._isShaking) {
										game._isShaking = true;
										var originalGameX = game.x || 0;
										var originalGameY = game.y || 0;
										var shakeAmount = 420; // extremely strong shake
										var shakeDuration = 420;
										tween(game, {
											x: originalGameX + (Math.random() - 0.5) * shakeAmount,
											y: originalGameY + (Math.random() - 0.5) * shakeAmount
										}, {
											duration: shakeDuration,
											onFinish: function onFinish() {
												tween(game, {
													x: originalGameX,
													y: originalGameY
												}, {
													duration: shakeDuration,
													onFinish: function onFinish() {
														game._isShaking = false;
													}
												});
											}
										});
									}
								}
							} else if (combo > 0 && combo % 10 === 0) {
								// All people jump!
								for (var iAll = 0; iAll < peopleLeft.length; iAll++) {
									if (peopleLeft[iAll]) peopleLeft[iAll].jump();
								}
								for (var iAll = 0; iAll < peopleRight.length; iAll++) {
									if (peopleRight[iAll]) peopleRight[iAll].jump();
								}
								// Stronger shake: override game.x/y with a bigger shake
								if (typeof game !== "undefined" && typeof tween !== "undefined") {
									if (!game._isShaking) {
										game._isShaking = true;
										var originalGameX = game.x || 0;
										var originalGameY = game.y || 0;
										var shakeAmount = 60; // much stronger shake
										var shakeDuration = 120;
										tween(game, {
											x: originalGameX + (Math.random() - 0.5) * shakeAmount,
											y: originalGameY + (Math.random() - 0.5) * shakeAmount
										}, {
											duration: shakeDuration,
											onFinish: function onFinish() {
												tween(game, {
													x: originalGameX,
													y: originalGameY
												}, {
													duration: shakeDuration,
													onFinish: function onFinish() {
														game._isShaking = false;
													}
												});
											}
										});
									}
								}
							} else {
								// Helper to get unique random indices
								var getRandomIndices = function getRandomIndices(arrLen, count) {
									var indices = [];
									var used = [];
									while (indices.length < count && indices.length < arrLen) {
										var idx = Math.floor(Math.random() * arrLen);
										if (!used[idx]) {
											indices.push(idx);
											used[idx] = true;
										}
									}
									return indices;
								};
								// How many people to jump per side? 1-3 random per side
								leftJumpCount = 1 + Math.floor(Math.random() * 3);
								rightJumpCount = 1 + Math.floor(Math.random() * 3);
								leftIndices = getRandomIndices(peopleLeft.length, leftJumpCount);
								rightIndices = getRandomIndices(peopleRight.length, rightJumpCount);
								for (j = 0; j < leftIndices.length; j++) {
									idx = leftIndices[j];
									if (peopleLeft[idx]) peopleLeft[idx].jump();
								}
								for (j = 0; j < rightIndices.length; j++) {
									idx = rightIndices[j];
									if (peopleRight[idx]) peopleRight[idx].jump();
								}
							}
						}
						// Show floating feedback text based on combo
						feedbackText = '';
						if (combo >= 30) {
							feedbackText = 'PERFECT!';
						} else if (combo >= 15) {
							feedbackText = 'GREAT!';
						} else if (combo >= 5) {
							feedbackText = 'GOOD!';
						}
						if (feedbackText) {
							fbTxt = new Text2(feedbackText, {
								size: 120,
								fill: 0xFFD700,
								font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
							});
							fbTxt.anchor.set(0.5, 0.5);
							fbTxt.x = GAME_WIDTH / 2;
							fbTxt.y = GAME_HEIGHT / 2 - 200;
							fbTxt.alpha = 1;
							game.addChild(fbTxt);
							tween(fbTxt, {
								y: fbTxt.y - 120,
								alpha: 0
							}, {
								duration: 700,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									fbTxt.destroy();
								}
							});
						}
						return 1; // break
					}
				},
				note,
				noteLeft,
				noteRight,
				noteTop,
				noteBottom,
				leftJumpCount,
				rightJumpCount,
				leftIndices,
				rightIndices,
				j,
				idx,
				j,
				idx,
				feedbackText,
				fbTxt,
				_ret;
			for (var i = notes.length - 1; i >= 0; i--) {
				_ret = _loop();
				if (_ret === 0) continue;
				if (_ret === 1) break;
			}
			if (!hit) {
				// Missed tap (no note hit)
				combo = 0;
				comboTxt.setText('');
				// No misses for tap misses, no flash
			}
		};
	}
};
// Do not start the song immediately; wait for user tap
// startSong();; ===================================================================
--- original.js
+++ change.js
@@ -496,9 +496,9 @@
 var lanes = [];
 var targets = [];
 var peopleLeft = [];
 var peopleRight = [];
-var currentPeoplePerSide = 3; // Track current number of people per side
+var currentPeoplePerSide = 0; // Track current number of people per side
 var lastScoreMilestone = 0; // Track last score milestone for adding people
 var targetMissTexts = []; // Miss counters for each target
 var laneContainers = []; // Containers to group lane elements together
 for (var i = 0; i < NUM_LANES; i++) {
@@ -567,9 +567,9 @@
 // Place people only outside the lanes, never over the road/lane area
 // --- Randomized, non-overlapping, not-in-center people placement ---
 peopleLeft = [];
 peopleRight = [];
-var NUM_PEOPLE_PER_EDGE = 3; // Start with only 3 people per side
+var NUM_PEOPLE_PER_EDGE = 0; // Start with no people
 var PERSON_RADIUS = 90; // Half of body width, for spacing
 var OUTER_X_OFFSET = 120; // How far outside the lane edge to place people
 // Allow people to go all the way to the screen edge, not just near the lanes
 var FAR_LEFT_X_MIN = 60;
@@ -602,41 +602,8 @@
 	var distLeft = Math.sqrt((x - leftDrumX) * (x - leftDrumX) + (y - leftDrumY) * (y - leftDrumY));
 	var distRight = Math.sqrt((x - rightDrumX) * (x - rightDrumX) + (y - rightDrumY) * (y - rightDrumY));
 	return distLeft > drumRadius && distRight > drumRadius;
 }
-// Check if position is not in drum area
-// Left edge: randomize y, keep x always outside leftmost lane, avoid center, avoid overlap, avoid drum
-for (var i = 0; i < NUM_PEOPLE_PER_EDGE; i++) {
-	var leftPerson = new People();
-	var attempts = 0;
-	var px, py;
-	do {
-		py = Y_MIN + Math.random() * (Y_MAX - Y_MIN);
-		// Randomize x across the full left empty area
-		px = FAR_LEFT_X_MIN + Math.random() * (FAR_LEFT_X_MAX - FAR_LEFT_X_MIN);
-		attempts++;
-	} while ((!isFarEnough(px, py, peopleLeft) || !isNotCenter(px) || !isNotDrumArea(px, py)) && attempts < MAX_ATTEMPTS);
-	leftPerson.x = px;
-	leftPerson.y = py;
-	game.addChild(leftPerson);
-	peopleLeft.push(leftPerson);
-}
-// Right edge: randomize y, keep x always outside rightmost lane, avoid center, avoid overlap, avoid drum
-for (var i = 0; i < NUM_PEOPLE_PER_EDGE; i++) {
-	var rightPerson = new People();
-	var attempts = 0;
-	var px, py;
-	do {
-		py = Y_MIN + Math.random() * (Y_MAX - Y_MIN);
-		// Randomize x across the full right empty area
-		px = FAR_RIGHT_X_MIN + Math.random() * (FAR_RIGHT_X_MAX - FAR_RIGHT_X_MIN);
-		attempts++;
-	} while ((!isFarEnough(px, py, peopleRight) || !isNotCenter(px) || !isNotDrumArea(px, py)) && attempts < MAX_ATTEMPTS);
-	rightPerson.x = px;
-	rightPerson.y = py;
-	game.addChild(rightPerson);
-	peopleRight.push(rightPerson);
-}
 // Update popularity after recreating people
 updatePopularity();
 // Update initial popularity
 updatePopularity();
@@ -765,11 +732,11 @@
 	}
 	// Re-create peopleLeft and peopleRight, but keep them away from drum asset positions
 	peopleLeft = [];
 	peopleRight = [];
-	currentPeoplePerSide = 3; // Reset to 3 people per side
+	currentPeoplePerSide = 0; // Reset to 0 people per side
 	lastScoreMilestone = 0; // Reset score milestone
-	var NUM_PEOPLE_PER_EDGE = 3; // Start with only 3 people per side
+	var NUM_PEOPLE_PER_EDGE = 0; // Start with no people
 	var PERSON_RADIUS = 90;
 	var OUTER_X_OFFSET = 120;
 	var FAR_LEFT_X_MIN = 60;
 	var FAR_LEFT_X_MAX = getLaneX(0) - LANE_WIDTH / 2 - OUTER_X_OFFSET - 10;
@@ -790,38 +757,9 @@
 	}
 	function isNotCenter(x) {
 		return !(x > CENTER_EXCLUSION_X && x < CENTER_EXCLUSION_X + CENTER_EXCLUSION_WIDTH);
 	}
-	// Left edge
-	for (var i = 0; i < NUM_PEOPLE_PER_EDGE; i++) {
-		var leftPerson = new People();
-		var attempts = 0;
-		var px, py;
-		do {
-			py = Y_MIN + Math.random() * (Y_MAX - Y_MIN);
-			px = FAR_LEFT_X_MIN + Math.random() * (FAR_LEFT_X_MAX - FAR_LEFT_X_MIN);
-			attempts++;
-		} while ((!isFarEnough(px, py, peopleLeft) || !isNotCenter(px) || !isNotDrumArea(px, py)) && attempts < MAX_ATTEMPTS);
-		leftPerson.x = px;
-		leftPerson.y = py;
-		game.addChild(leftPerson);
-		peopleLeft.push(leftPerson);
-	}
-	// Right edge
-	for (var i = 0; i < NUM_PEOPLE_PER_EDGE; i++) {
-		var rightPerson = new People();
-		var attempts = 0;
-		var px, py;
-		do {
-			py = Y_MIN + Math.random() * (Y_MAX - Y_MIN);
-			px = FAR_RIGHT_X_MIN + Math.random() * (FAR_RIGHT_X_MAX - FAR_RIGHT_X_MIN);
-			attempts++;
-		} while ((!isFarEnough(px, py, peopleRight) || !isNotCenter(px) || !isNotDrumArea(px, py)) && attempts < MAX_ATTEMPTS);
-		rightPerson.x = px;
-		rightPerson.y = py;
-		game.addChild(rightPerson);
-		peopleRight.push(rightPerson);
-	}
+	// No people are created at the start
 	// Create left drum after people to ensure it appears in front
 	leftDrum = LK.getAsset('drumV2', {
 		anchorX: 0.5,
 		anchorY: 0.5,