Code edit (1 edits merged)
Please save this source code
User prompt
Sing Along Studio
Initial prompt
Toca singing 2 (2017). Hold the mic 🎤 up nealty and now you try. Sing let it go and sing along with Elsa 🩵. Tap on the French button, or the Castilian Spanish button to make Elsa 🩵 sing in 2 different ways.
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var facekit = LK.import("@upit/facekit.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var LanguageButton = Container.expand(function (language) {
	var self = Container.call(this);
	var buttonBg = self.attachAsset('languageButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var langText = new Text2(language, {
		size: 30,
		fill: 0xFFFFFF
	});
	langText.anchor.set(0.5, 0.5);
	self.addChild(langText);
	self.language = language;
	self.down = function (x, y, obj) {
		currentLanguage = self.language;
		updateLanguageButtons();
		tween(buttonBg, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 100
		});
	};
	self.up = function (x, y, obj) {
		tween(buttonBg, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 100
		});
	};
	return self;
});
var SongButton = Container.expand(function (songData) {
	var self = Container.call(this);
	var buttonBg = self.attachAsset('songButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var titleText = new Text2(songData.title, {
		size: 40,
		fill: 0xFFFFFF
	});
	titleText.anchor.set(0.5, 0.5);
	self.addChild(titleText);
	self.songData = songData;
	self.down = function (x, y, obj) {
		selectedSong = self.songData;
		gameState = 'playing';
		initializeSong();
		tween(buttonBg, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 100
		});
	};
	self.up = function (x, y, obj) {
		tween(buttonBg, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 100
		});
	};
	return self;
});
var TargetNote = Container.expand(function (pitch, time) {
	var self = Container.call(this);
	var note = self.attachAsset('targetNote', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.targetPitch = pitch;
	self.targetTime = time;
	return self;
});
var VoiceParticle = Container.expand(function () {
	var self = Container.call(this);
	var particle = self.attachAsset('particle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.life = 1.0;
	self.velocityX = (Math.random() - 0.5) * 200;
	self.velocityY = (Math.random() - 0.5) * 200;
	self.update = function () {
		self.x += self.velocityX * 0.016;
		self.y += self.velocityY * 0.016;
		self.life -= 0.02;
		particle.alpha = self.life;
		particle.scaleX = self.life;
		particle.scaleY = self.life;
		if (self.life <= 0) {
			self.destroy();
			var index = particles.indexOf(self);
			if (index > -1) {
				particles.splice(index, 1);
			}
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x1A1A2E
});
/**** 
* Game Code
****/ 
// Game state management
var gameState = 'menu'; // 'menu', 'playing', 'results'
var currentLanguage = 'English';
var selectedSong = null;
var songProgress = 0;
var songStartTime = 0;
var score = 0;
var maxScore = 100;
// Voice tracking
var lastVolume = 0;
var lastPitch = 0;
var pitchHistory = [];
var volumeHistory = [];
// Visual elements
var particles = [];
var targetNotes = [];
var languageButtons = [];
var songButtons = [];
// Song data
var songs = [{
	id: 'twinkle',
	title: 'Twinkle Twinkle',
	duration: 12000,
	lyrics: {
		'English': [{
			text: 'Twinkle, twinkle, little star',
			time: 0,
			duration: 3000
		}, {
			text: 'How I wonder what you are',
			time: 3000,
			duration: 3000
		}, {
			text: 'Up above the world so high',
			time: 6000,
			duration: 3000
		}, {
			text: 'Like a diamond in the sky',
			time: 9000,
			duration: 3000
		}],
		'Spanish': [{
			text: 'Estrellita, dónde estás',
			time: 0,
			duration: 3000
		}, {
			text: 'Me pregunto qué serás',
			time: 3000,
			duration: 3000
		}, {
			text: 'En el cielo, tan arriba',
			time: 6000,
			duration: 3000
		}, {
			text: 'Como un diamante que brilla',
			time: 9000,
			duration: 3000
		}],
		'French': [{
			text: 'Brille, brille, petite étoile',
			time: 0,
			duration: 3000
		}, {
			text: 'Je me demande ce que tu es',
			time: 3000,
			duration: 3000
		}, {
			text: 'Là-haut dans le ciel si haut',
			time: 6000,
			duration: 3000
		}, {
			text: 'Comme un diamant là-haut',
			time: 9000,
			duration: 3000
		}]
	},
	targetPitches: [{
		pitch: 200,
		time: 0
	}, {
		pitch: 200,
		time: 500
	}, {
		pitch: 300,
		time: 1000
	}, {
		pitch: 300,
		time: 1500
	}, {
		pitch: 350,
		time: 2000
	}, {
		pitch: 350,
		time: 2500
	}, {
		pitch: 300,
		time: 3000
	}, {
		pitch: 250,
		time: 3500
	}, {
		pitch: 250,
		time: 4000
	}, {
		pitch: 200,
		time: 4500
	}, {
		pitch: 200,
		time: 5000
	}, {
		pitch: 150,
		time: 5500
	}]
}, {
	id: 'happy',
	title: 'Happy Birthday',
	duration: 15000,
	lyrics: {
		'English': [{
			text: 'Happy birthday to you',
			time: 0,
			duration: 3000
		}, {
			text: 'Happy birthday to you',
			time: 3000,
			duration: 3000
		}, {
			text: 'Happy birthday dear friend',
			time: 6000,
			duration: 4500
		}, {
			text: 'Happy birthday to you',
			time: 10500,
			duration: 4500
		}],
		'Spanish': [{
			text: 'Cumpleaños feliz',
			time: 0,
			duration: 3000
		}, {
			text: 'Cumpleaños feliz',
			time: 3000,
			duration: 3000
		}, {
			text: 'Te deseamos amigo',
			time: 6000,
			duration: 4500
		}, {
			text: 'Cumpleaños feliz',
			time: 10500,
			duration: 4500
		}],
		'French': [{
			text: 'Joyeux anniversaire',
			time: 0,
			duration: 3000
		}, {
			text: 'Joyeux anniversaire',
			time: 3000,
			duration: 3000
		}, {
			text: 'Joyeux anniversaire mon ami',
			time: 6000,
			duration: 4500
		}, {
			text: 'Joyeux anniversaire',
			time: 10500,
			duration: 4500
		}]
	},
	targetPitches: [{
		pitch: 180,
		time: 0
	}, {
		pitch: 180,
		time: 500
	}, {
		pitch: 220,
		time: 1000
	}, {
		pitch: 180,
		time: 1500
	}, {
		pitch: 260,
		time: 2000
	}, {
		pitch: 240,
		time: 2500
	}]
}];
// UI Elements
var titleText = new Text2('Sing Along Studio', {
	size: 80,
	fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 200;
game.addChild(titleText);
var micIcon = game.attachAsset('microphoneIcon', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 1024,
	y: 400
});
var volumeBar = game.attachAsset('noteBar', {
	anchorX: 0,
	anchorY: 0.5,
	x: 624,
	y: 500
});
var pitchIndicator = game.attachAsset('playerNote', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 1024,
	y: 600
});
var lyricBg = game.attachAsset('lyricBackground', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 1024,
	y: 2400
});
lyricBg.alpha = 0.8;
var currentLyricText = new Text2('', {
	size: 50,
	fill: 0xFFFFFF
});
currentLyricText.anchor.set(0.5, 0.5);
currentLyricText.x = 1024;
currentLyricText.y = 2400;
game.addChild(currentLyricText);
var scoreText = new Text2('Score: 0', {
	size: 40,
	fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Language buttons
var languages = ['English', 'Spanish', 'French'];
for (var i = 0; i < languages.length; i++) {
	var langBtn = new LanguageButton(languages[i]);
	langBtn.x = 400 + i * 250;
	langBtn.y = 1000;
	game.addChild(langBtn);
	languageButtons.push(langBtn);
}
// Song selection buttons
for (var i = 0; i < songs.length; i++) {
	var songBtn = new SongButton(songs[i]);
	songBtn.x = 1024;
	songBtn.y = 1300 + i * 150;
	game.addChild(songBtn);
	songButtons.push(songBtn);
}
// Back button
var backButton = game.attachAsset('languageButton', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 200,
	y: 150
});
var backText = new Text2('Back', {
	size: 30,
	fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 200;
backText.y = 150;
game.addChild(backText);
function updateLanguageButtons() {
	for (var i = 0; i < languageButtons.length; i++) {
		var btn = languageButtons[i];
		if (btn.language === currentLanguage) {
			tween(btn, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 200
			});
		} else {
			tween(btn, {
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 200
			});
		}
	}
}
function initializeSong() {
	if (!selectedSong) return;
	songStartTime = LK.ticks;
	songProgress = 0;
	score = 0;
	// Clear existing target notes
	for (var i = 0; i < targetNotes.length; i++) {
		targetNotes[i].destroy();
	}
	targetNotes = [];
	// Hide menu elements
	titleText.visible = false;
	for (var i = 0; i < languageButtons.length; i++) {
		languageButtons[i].visible = false;
	}
	for (var i = 0; i < songButtons.length; i++) {
		songButtons[i].visible = false;
	}
	// Show game elements
	lyricBg.visible = true;
	currentLyricText.visible = true;
}
function endSong() {
	gameState = 'results';
	// Calculate final score
	var finalScore = Math.floor(score / maxScore * 100);
	LK.setScore(finalScore);
	// Show results
	currentLyricText.setText('Great job! Score: ' + finalScore + '%');
	// Auto return to menu after 3 seconds
	LK.setTimeout(function () {
		returnToMenu();
	}, 3000);
}
function returnToMenu() {
	gameState = 'menu';
	selectedSong = null;
	// Show menu elements
	titleText.visible = true;
	for (var i = 0; i < languageButtons.length; i++) {
		languageButtons[i].visible = true;
	}
	for (var i = 0; i < songButtons.length; i++) {
		songButtons[i].visible = true;
	}
	// Hide game elements
	lyricBg.visible = false;
	currentLyricText.visible = false;
	currentLyricText.setText('');
}
function createVoiceParticles() {
	if (facekit.volume > 0.3) {
		for (var i = 0; i < 3; i++) {
			var particle = new VoiceParticle();
			particle.x = micIcon.x + (Math.random() - 0.5) * 100;
			particle.y = micIcon.y + (Math.random() - 0.5) * 100;
			game.addChild(particle);
			particles.push(particle);
		}
	}
}
function updatePitchVisualization() {
	var targetY = 600;
	if (facekit.pitch > 0) {
		// Map pitch to vertical position (lower pitch = lower on screen)
		targetY = 800 - facekit.pitch / 400 * 300;
		targetY = Math.max(400, Math.min(800, targetY));
	}
	tween(pitchIndicator, {
		y: targetY
	}, {
		duration: 100
	});
	// Update pitch indicator size based on volume
	var scale = 0.5 + facekit.volume * 1.5;
	tween(pitchIndicator, {
		scaleX: scale,
		scaleY: scale
	}, {
		duration: 100
	});
}
function updateVolumeBar() {
	var barWidth = facekit.volume * 800;
	tween(volumeBar, {
		width: barWidth
	}, {
		duration: 100
	});
}
function calculatePitchScore() {
	if (!selectedSong || gameState !== 'playing') return;
	var currentTime = LK.ticks - songStartTime;
	var timeInMs = currentTime / 60 * 1000;
	// Find closest target pitch
	var closestPitch = null;
	var minTimeDiff = Infinity;
	for (var i = 0; i < selectedSong.targetPitches.length; i++) {
		var targetPitch = selectedSong.targetPitches[i];
		var timeDiff = Math.abs(targetPitch.time - timeInMs);
		if (timeDiff < minTimeDiff && timeDiff < 1000) {
			minTimeDiff = timeDiff;
			closestPitch = targetPitch;
		}
	}
	if (closestPitch && facekit.pitch > 0) {
		var pitchDiff = Math.abs(facekit.pitch - closestPitch.pitch);
		var pitchScore = Math.max(0, 1 - pitchDiff / 100);
		var volumeBonus = facekit.volume > 0.3 ? 1 : 0.5;
		score += pitchScore * volumeBonus * 0.1;
		score = Math.min(score, maxScore);
	}
}
function updateCurrentLyric() {
	if (!selectedSong || gameState !== 'playing') return;
	var currentTime = LK.ticks - songStartTime;
	var timeInMs = currentTime / 60 * 1000;
	var lyrics = selectedSong.lyrics[currentLanguage];
	var currentLyric = '';
	for (var i = 0; i < lyrics.length; i++) {
		var lyric = lyrics[i];
		if (timeInMs >= lyric.time && timeInMs < lyric.time + lyric.duration) {
			currentLyric = lyric.text;
			break;
		}
	}
	if (currentLyricText.text !== currentLyric) {
		currentLyricText.setText(currentLyric);
		if (currentLyric !== '') {
			tween(currentLyricText, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 200,
				onFinish: function onFinish() {
					tween(currentLyricText, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 200
					});
				}
			});
		}
	}
}
// Event handlers
game.down = function (x, y, obj) {
	if (gameState === 'results' || gameState === 'playing') {
		// Check if back button clicked
		if (x < 300 && y < 250) {
			returnToMenu();
		}
	}
};
// Initialize menu state
updateLanguageButtons();
lyricBg.visible = false;
currentLyricText.visible = false;
game.update = function () {
	// Update volume history
	volumeHistory.push(facekit.volume);
	if (volumeHistory.length > 30) {
		volumeHistory.shift();
	}
	// Update pitch history
	pitchHistory.push(facekit.pitch);
	if (pitchHistory.length > 30) {
		pitchHistory.shift();
	}
	// Update visual feedback
	updateVolumeBar();
	updatePitchVisualization();
	// Create particles based on voice input
	if (LK.ticks % 10 === 0) {
		createVoiceParticles();
	}
	// Update score display
	scoreText.setText('Score: ' + Math.floor(score));
	if (gameState === 'playing' && selectedSong) {
		var currentTime = LK.ticks - songStartTime;
		var timeInMs = currentTime / 60 * 1000;
		// Update lyrics
		updateCurrentLyric();
		// Calculate pitch accuracy score
		calculatePitchScore();
		// Check if song is finished
		if (timeInMs >= selectedSong.duration) {
			endSong();
		}
		// Add visual effects for good singing
		if (facekit.volume > 0.6 && facekit.pitch > 100) {
			LK.effects.flashObject(micIcon, 0x4CAF50, 200);
		}
	}
	// Animate microphone icon based on volume
	if (facekit.volume > 0.1) {
		var pulse = 1 + facekit.volume * 0.3;
		micIcon.scaleX = pulse;
		micIcon.scaleY = pulse;
	} else {
		tween(micIcon, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 200
		});
	}
	// Color microphone based on pitch detection
	if (facekit.pitch > 50) {
		tween(micIcon, {
			tint: 0x4CAF50
		}, {
			duration: 200
		});
	} else {
		tween(micIcon, {
			tint: 0xFFFFFF
		}, {
			duration: 200
		});
	}
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,637 @@
-/****
+/**** 
+* Plugins
+****/ 
+var tween = LK.import("@upit/tween.v1");
+var facekit = LK.import("@upit/facekit.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/**** 
+* Classes
+****/ 
+var LanguageButton = Container.expand(function (language) {
+	var self = Container.call(this);
+	var buttonBg = self.attachAsset('languageButton', {
+		anchorX: 0.5,
+		anchorY: 0.5
+	});
+	var langText = new Text2(language, {
+		size: 30,
+		fill: 0xFFFFFF
+	});
+	langText.anchor.set(0.5, 0.5);
+	self.addChild(langText);
+	self.language = language;
+	self.down = function (x, y, obj) {
+		currentLanguage = self.language;
+		updateLanguageButtons();
+		tween(buttonBg, {
+			scaleX: 0.9,
+			scaleY: 0.9
+		}, {
+			duration: 100
+		});
+	};
+	self.up = function (x, y, obj) {
+		tween(buttonBg, {
+			scaleX: 1,
+			scaleY: 1
+		}, {
+			duration: 100
+		});
+	};
+	return self;
+});
+var SongButton = Container.expand(function (songData) {
+	var self = Container.call(this);
+	var buttonBg = self.attachAsset('songButton', {
+		anchorX: 0.5,
+		anchorY: 0.5
+	});
+	var titleText = new Text2(songData.title, {
+		size: 40,
+		fill: 0xFFFFFF
+	});
+	titleText.anchor.set(0.5, 0.5);
+	self.addChild(titleText);
+	self.songData = songData;
+	self.down = function (x, y, obj) {
+		selectedSong = self.songData;
+		gameState = 'playing';
+		initializeSong();
+		tween(buttonBg, {
+			scaleX: 0.9,
+			scaleY: 0.9
+		}, {
+			duration: 100
+		});
+	};
+	self.up = function (x, y, obj) {
+		tween(buttonBg, {
+			scaleX: 1,
+			scaleY: 1
+		}, {
+			duration: 100
+		});
+	};
+	return self;
+});
+var TargetNote = Container.expand(function (pitch, time) {
+	var self = Container.call(this);
+	var note = self.attachAsset('targetNote', {
+		anchorX: 0.5,
+		anchorY: 0.5
+	});
+	self.targetPitch = pitch;
+	self.targetTime = time;
+	return self;
+});
+var VoiceParticle = Container.expand(function () {
+	var self = Container.call(this);
+	var particle = self.attachAsset('particle', {
+		anchorX: 0.5,
+		anchorY: 0.5
+	});
+	self.life = 1.0;
+	self.velocityX = (Math.random() - 0.5) * 200;
+	self.velocityY = (Math.random() - 0.5) * 200;
+	self.update = function () {
+		self.x += self.velocityX * 0.016;
+		self.y += self.velocityY * 0.016;
+		self.life -= 0.02;
+		particle.alpha = self.life;
+		particle.scaleX = self.life;
+		particle.scaleY = self.life;
+		if (self.life <= 0) {
+			self.destroy();
+			var index = particles.indexOf(self);
+			if (index > -1) {
+				particles.splice(index, 1);
+			}
+		}
+	};
+	return self;
+});
+
+/**** 
 * Initialize Game
-****/
+****/ 
 var game = new LK.Game({
-	backgroundColor: 0x000000
-});
\ No newline at end of file
+	backgroundColor: 0x1A1A2E
+});
+
+/**** 
+* Game Code
+****/ 
+// Game state management
+var gameState = 'menu'; // 'menu', 'playing', 'results'
+var currentLanguage = 'English';
+var selectedSong = null;
+var songProgress = 0;
+var songStartTime = 0;
+var score = 0;
+var maxScore = 100;
+// Voice tracking
+var lastVolume = 0;
+var lastPitch = 0;
+var pitchHistory = [];
+var volumeHistory = [];
+// Visual elements
+var particles = [];
+var targetNotes = [];
+var languageButtons = [];
+var songButtons = [];
+// Song data
+var songs = [{
+	id: 'twinkle',
+	title: 'Twinkle Twinkle',
+	duration: 12000,
+	lyrics: {
+		'English': [{
+			text: 'Twinkle, twinkle, little star',
+			time: 0,
+			duration: 3000
+		}, {
+			text: 'How I wonder what you are',
+			time: 3000,
+			duration: 3000
+		}, {
+			text: 'Up above the world so high',
+			time: 6000,
+			duration: 3000
+		}, {
+			text: 'Like a diamond in the sky',
+			time: 9000,
+			duration: 3000
+		}],
+		'Spanish': [{
+			text: 'Estrellita, dónde estás',
+			time: 0,
+			duration: 3000
+		}, {
+			text: 'Me pregunto qué serás',
+			time: 3000,
+			duration: 3000
+		}, {
+			text: 'En el cielo, tan arriba',
+			time: 6000,
+			duration: 3000
+		}, {
+			text: 'Como un diamante que brilla',
+			time: 9000,
+			duration: 3000
+		}],
+		'French': [{
+			text: 'Brille, brille, petite étoile',
+			time: 0,
+			duration: 3000
+		}, {
+			text: 'Je me demande ce que tu es',
+			time: 3000,
+			duration: 3000
+		}, {
+			text: 'Là-haut dans le ciel si haut',
+			time: 6000,
+			duration: 3000
+		}, {
+			text: 'Comme un diamant là-haut',
+			time: 9000,
+			duration: 3000
+		}]
+	},
+	targetPitches: [{
+		pitch: 200,
+		time: 0
+	}, {
+		pitch: 200,
+		time: 500
+	}, {
+		pitch: 300,
+		time: 1000
+	}, {
+		pitch: 300,
+		time: 1500
+	}, {
+		pitch: 350,
+		time: 2000
+	}, {
+		pitch: 350,
+		time: 2500
+	}, {
+		pitch: 300,
+		time: 3000
+	}, {
+		pitch: 250,
+		time: 3500
+	}, {
+		pitch: 250,
+		time: 4000
+	}, {
+		pitch: 200,
+		time: 4500
+	}, {
+		pitch: 200,
+		time: 5000
+	}, {
+		pitch: 150,
+		time: 5500
+	}]
+}, {
+	id: 'happy',
+	title: 'Happy Birthday',
+	duration: 15000,
+	lyrics: {
+		'English': [{
+			text: 'Happy birthday to you',
+			time: 0,
+			duration: 3000
+		}, {
+			text: 'Happy birthday to you',
+			time: 3000,
+			duration: 3000
+		}, {
+			text: 'Happy birthday dear friend',
+			time: 6000,
+			duration: 4500
+		}, {
+			text: 'Happy birthday to you',
+			time: 10500,
+			duration: 4500
+		}],
+		'Spanish': [{
+			text: 'Cumpleaños feliz',
+			time: 0,
+			duration: 3000
+		}, {
+			text: 'Cumpleaños feliz',
+			time: 3000,
+			duration: 3000
+		}, {
+			text: 'Te deseamos amigo',
+			time: 6000,
+			duration: 4500
+		}, {
+			text: 'Cumpleaños feliz',
+			time: 10500,
+			duration: 4500
+		}],
+		'French': [{
+			text: 'Joyeux anniversaire',
+			time: 0,
+			duration: 3000
+		}, {
+			text: 'Joyeux anniversaire',
+			time: 3000,
+			duration: 3000
+		}, {
+			text: 'Joyeux anniversaire mon ami',
+			time: 6000,
+			duration: 4500
+		}, {
+			text: 'Joyeux anniversaire',
+			time: 10500,
+			duration: 4500
+		}]
+	},
+	targetPitches: [{
+		pitch: 180,
+		time: 0
+	}, {
+		pitch: 180,
+		time: 500
+	}, {
+		pitch: 220,
+		time: 1000
+	}, {
+		pitch: 180,
+		time: 1500
+	}, {
+		pitch: 260,
+		time: 2000
+	}, {
+		pitch: 240,
+		time: 2500
+	}]
+}];
+// UI Elements
+var titleText = new Text2('Sing Along Studio', {
+	size: 80,
+	fill: 0xFFFFFF
+});
+titleText.anchor.set(0.5, 0.5);
+titleText.x = 1024;
+titleText.y = 200;
+game.addChild(titleText);
+var micIcon = game.attachAsset('microphoneIcon', {
+	anchorX: 0.5,
+	anchorY: 0.5,
+	x: 1024,
+	y: 400
+});
+var volumeBar = game.attachAsset('noteBar', {
+	anchorX: 0,
+	anchorY: 0.5,
+	x: 624,
+	y: 500
+});
+var pitchIndicator = game.attachAsset('playerNote', {
+	anchorX: 0.5,
+	anchorY: 0.5,
+	x: 1024,
+	y: 600
+});
+var lyricBg = game.attachAsset('lyricBackground', {
+	anchorX: 0.5,
+	anchorY: 0.5,
+	x: 1024,
+	y: 2400
+});
+lyricBg.alpha = 0.8;
+var currentLyricText = new Text2('', {
+	size: 50,
+	fill: 0xFFFFFF
+});
+currentLyricText.anchor.set(0.5, 0.5);
+currentLyricText.x = 1024;
+currentLyricText.y = 2400;
+game.addChild(currentLyricText);
+var scoreText = new Text2('Score: 0', {
+	size: 40,
+	fill: 0xFFFFFF
+});
+scoreText.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreText);
+// Language buttons
+var languages = ['English', 'Spanish', 'French'];
+for (var i = 0; i < languages.length; i++) {
+	var langBtn = new LanguageButton(languages[i]);
+	langBtn.x = 400 + i * 250;
+	langBtn.y = 1000;
+	game.addChild(langBtn);
+	languageButtons.push(langBtn);
+}
+// Song selection buttons
+for (var i = 0; i < songs.length; i++) {
+	var songBtn = new SongButton(songs[i]);
+	songBtn.x = 1024;
+	songBtn.y = 1300 + i * 150;
+	game.addChild(songBtn);
+	songButtons.push(songBtn);
+}
+// Back button
+var backButton = game.attachAsset('languageButton', {
+	anchorX: 0.5,
+	anchorY: 0.5,
+	x: 200,
+	y: 150
+});
+var backText = new Text2('Back', {
+	size: 30,
+	fill: 0xFFFFFF
+});
+backText.anchor.set(0.5, 0.5);
+backText.x = 200;
+backText.y = 150;
+game.addChild(backText);
+function updateLanguageButtons() {
+	for (var i = 0; i < languageButtons.length; i++) {
+		var btn = languageButtons[i];
+		if (btn.language === currentLanguage) {
+			tween(btn, {
+				scaleX: 1.2,
+				scaleY: 1.2
+			}, {
+				duration: 200
+			});
+		} else {
+			tween(btn, {
+				scaleX: 1,
+				scaleY: 1
+			}, {
+				duration: 200
+			});
+		}
+	}
+}
+function initializeSong() {
+	if (!selectedSong) return;
+	songStartTime = LK.ticks;
+	songProgress = 0;
+	score = 0;
+	// Clear existing target notes
+	for (var i = 0; i < targetNotes.length; i++) {
+		targetNotes[i].destroy();
+	}
+	targetNotes = [];
+	// Hide menu elements
+	titleText.visible = false;
+	for (var i = 0; i < languageButtons.length; i++) {
+		languageButtons[i].visible = false;
+	}
+	for (var i = 0; i < songButtons.length; i++) {
+		songButtons[i].visible = false;
+	}
+	// Show game elements
+	lyricBg.visible = true;
+	currentLyricText.visible = true;
+}
+function endSong() {
+	gameState = 'results';
+	// Calculate final score
+	var finalScore = Math.floor(score / maxScore * 100);
+	LK.setScore(finalScore);
+	// Show results
+	currentLyricText.setText('Great job! Score: ' + finalScore + '%');
+	// Auto return to menu after 3 seconds
+	LK.setTimeout(function () {
+		returnToMenu();
+	}, 3000);
+}
+function returnToMenu() {
+	gameState = 'menu';
+	selectedSong = null;
+	// Show menu elements
+	titleText.visible = true;
+	for (var i = 0; i < languageButtons.length; i++) {
+		languageButtons[i].visible = true;
+	}
+	for (var i = 0; i < songButtons.length; i++) {
+		songButtons[i].visible = true;
+	}
+	// Hide game elements
+	lyricBg.visible = false;
+	currentLyricText.visible = false;
+	currentLyricText.setText('');
+}
+function createVoiceParticles() {
+	if (facekit.volume > 0.3) {
+		for (var i = 0; i < 3; i++) {
+			var particle = new VoiceParticle();
+			particle.x = micIcon.x + (Math.random() - 0.5) * 100;
+			particle.y = micIcon.y + (Math.random() - 0.5) * 100;
+			game.addChild(particle);
+			particles.push(particle);
+		}
+	}
+}
+function updatePitchVisualization() {
+	var targetY = 600;
+	if (facekit.pitch > 0) {
+		// Map pitch to vertical position (lower pitch = lower on screen)
+		targetY = 800 - facekit.pitch / 400 * 300;
+		targetY = Math.max(400, Math.min(800, targetY));
+	}
+	tween(pitchIndicator, {
+		y: targetY
+	}, {
+		duration: 100
+	});
+	// Update pitch indicator size based on volume
+	var scale = 0.5 + facekit.volume * 1.5;
+	tween(pitchIndicator, {
+		scaleX: scale,
+		scaleY: scale
+	}, {
+		duration: 100
+	});
+}
+function updateVolumeBar() {
+	var barWidth = facekit.volume * 800;
+	tween(volumeBar, {
+		width: barWidth
+	}, {
+		duration: 100
+	});
+}
+function calculatePitchScore() {
+	if (!selectedSong || gameState !== 'playing') return;
+	var currentTime = LK.ticks - songStartTime;
+	var timeInMs = currentTime / 60 * 1000;
+	// Find closest target pitch
+	var closestPitch = null;
+	var minTimeDiff = Infinity;
+	for (var i = 0; i < selectedSong.targetPitches.length; i++) {
+		var targetPitch = selectedSong.targetPitches[i];
+		var timeDiff = Math.abs(targetPitch.time - timeInMs);
+		if (timeDiff < minTimeDiff && timeDiff < 1000) {
+			minTimeDiff = timeDiff;
+			closestPitch = targetPitch;
+		}
+	}
+	if (closestPitch && facekit.pitch > 0) {
+		var pitchDiff = Math.abs(facekit.pitch - closestPitch.pitch);
+		var pitchScore = Math.max(0, 1 - pitchDiff / 100);
+		var volumeBonus = facekit.volume > 0.3 ? 1 : 0.5;
+		score += pitchScore * volumeBonus * 0.1;
+		score = Math.min(score, maxScore);
+	}
+}
+function updateCurrentLyric() {
+	if (!selectedSong || gameState !== 'playing') return;
+	var currentTime = LK.ticks - songStartTime;
+	var timeInMs = currentTime / 60 * 1000;
+	var lyrics = selectedSong.lyrics[currentLanguage];
+	var currentLyric = '';
+	for (var i = 0; i < lyrics.length; i++) {
+		var lyric = lyrics[i];
+		if (timeInMs >= lyric.time && timeInMs < lyric.time + lyric.duration) {
+			currentLyric = lyric.text;
+			break;
+		}
+	}
+	if (currentLyricText.text !== currentLyric) {
+		currentLyricText.setText(currentLyric);
+		if (currentLyric !== '') {
+			tween(currentLyricText, {
+				scaleX: 1.2,
+				scaleY: 1.2
+			}, {
+				duration: 200,
+				onFinish: function onFinish() {
+					tween(currentLyricText, {
+						scaleX: 1,
+						scaleY: 1
+					}, {
+						duration: 200
+					});
+				}
+			});
+		}
+	}
+}
+// Event handlers
+game.down = function (x, y, obj) {
+	if (gameState === 'results' || gameState === 'playing') {
+		// Check if back button clicked
+		if (x < 300 && y < 250) {
+			returnToMenu();
+		}
+	}
+};
+// Initialize menu state
+updateLanguageButtons();
+lyricBg.visible = false;
+currentLyricText.visible = false;
+game.update = function () {
+	// Update volume history
+	volumeHistory.push(facekit.volume);
+	if (volumeHistory.length > 30) {
+		volumeHistory.shift();
+	}
+	// Update pitch history
+	pitchHistory.push(facekit.pitch);
+	if (pitchHistory.length > 30) {
+		pitchHistory.shift();
+	}
+	// Update visual feedback
+	updateVolumeBar();
+	updatePitchVisualization();
+	// Create particles based on voice input
+	if (LK.ticks % 10 === 0) {
+		createVoiceParticles();
+	}
+	// Update score display
+	scoreText.setText('Score: ' + Math.floor(score));
+	if (gameState === 'playing' && selectedSong) {
+		var currentTime = LK.ticks - songStartTime;
+		var timeInMs = currentTime / 60 * 1000;
+		// Update lyrics
+		updateCurrentLyric();
+		// Calculate pitch accuracy score
+		calculatePitchScore();
+		// Check if song is finished
+		if (timeInMs >= selectedSong.duration) {
+			endSong();
+		}
+		// Add visual effects for good singing
+		if (facekit.volume > 0.6 && facekit.pitch > 100) {
+			LK.effects.flashObject(micIcon, 0x4CAF50, 200);
+		}
+	}
+	// Animate microphone icon based on volume
+	if (facekit.volume > 0.1) {
+		var pulse = 1 + facekit.volume * 0.3;
+		micIcon.scaleX = pulse;
+		micIcon.scaleY = pulse;
+	} else {
+		tween(micIcon, {
+			scaleX: 1,
+			scaleY: 1
+		}, {
+			duration: 200
+		});
+	}
+	// Color microphone based on pitch detection
+	if (facekit.pitch > 50) {
+		tween(micIcon, {
+			tint: 0x4CAF50
+		}, {
+			duration: 200
+		});
+	} else {
+		tween(micIcon, {
+			tint: 0xFFFFFF
+		}, {
+			duration: 200
+		});
+	}
+};
\ No newline at end of file