User prompt
Name the scores by names accounts in upit if they are logged in. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Always show the highest score on the top and other scores below each other.
User prompt
Show the Closebutton front of background2 when highscorebutton is clicked.
User prompt
reorder close button with background2 to be front of it, The closebutton is behind background2!
User prompt
Replace the close in highscore background2 with the asset closebutton
User prompt
Add closebutton 100x100 in the right corner for the score background to quit from it
User prompt
Please fix the bug: 'Uncaught TypeError: storage.get is not a function' in or related to this line: 'var accountId = storage.get('accountId');' Line Number: 386 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Uncaught TypeError: storage.getAccountId is not a function' in or related to this line: 'var accountId = storage.getAccountId();' Line Number: 386
User prompt
save the score by ID of upit accounts if that possible so the scores will not deleted or rested.
User prompt
Add background2 as background when High score button is clicked, add texts below each other when new score of a player is added.
User prompt
Show the high score button in intro only
User prompt
Please fix the bug: 'Uncaught TypeError: storage.showMessage is not a function' in or related to this line: 'storage.showMessage(currentMessage);' Line Number: 286 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Uncaught TypeError: LK.showMessage is not a function' in or related to this line: 'LK.showMessage(currentMessage);' Line Number: 286
User prompt
Please fix the bug: 'Uncaught TypeError: LK.showHighscores is not a function' in or related to this line: 'LK.showHighscores();' Line Number: 282 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Add highscorebutton bellow the startbutton
User prompt
when click start button red color
User prompt
when click start button yellow color
User prompt
change the click color on the faces to purple
User prompt
Add scale to +100 then back like zoom animation for the startbutton
User prompt
Reduce the rotation to 10°
User prompt
Rotate the 'startbutton' 20° to the left back to 0° then rotate it 20° to the right continuously before game start. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hide score till game start
User prompt
Add music 'Intromusic1' for the intro before game start
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// Sound for when a meme reaches the bottom
// No plugins needed for this version.
// Class for the falling meme faces
var FallingMeme = Container.expand(function (memeType, speed) {
	var self = Container.call(this);
	self.memeType = memeType; // Store the type (e.g., 'meme1', 'meme5')
	self.speed = speed;
	// Attach the corresponding meme image asset
	var memeGraphics = self.attachAsset(memeType, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.assetWidth = memeGraphics.width; // Store dimensions for easier access
	self.assetHeight = memeGraphics.height;
	// Update function called by LK engine each frame
	self.update = function () {
		self.y += self.speed;
		// Update collision detection considering the current scale
		self.isOffScreen = function (gameHeight) {
			// Consider the meme off-screen if its top edge is past the bottom
			// Account for scaling
			return self.y - self.assetHeight * self.scale.y / 2 > gameHeight;
		};
	};
	// Method to check if the meme is off the bottom of the screen
	self.isOffScreen = function (gameHeight) {
		// Consider the meme off-screen if its top edge is past the bottom
		return self.y - self.assetHeight / 2 > gameHeight;
	};
	return self;
});
// Class for the buttons at the bottom
var MemeButton = Container.expand(function (memeType) {
	var self = Container.call(this);
	self.memeType = memeType; // Store the type (e.g., 'meme1', 'meme5')
	// Attach the corresponding meme image asset
	var buttonGraphics = self.attachAsset(memeType, {
		anchorX: 0.5,
		anchorY: 0.5
		// Removed scaling to make buttons 200x200
	});
	// Store dimensions for layout (now using full asset size)
	self.assetWidth = buttonGraphics.width;
	self.assetHeight = buttonGraphics.height;
	// Event handler for when the button is pressed
	// This will be automatically called by the LK engine if the button is attached
	self.down = function (x, y, obj) {
		// Find the lowest falling meme of the matching type
		var matchedMeme = null;
		var lowestY = -1;
		for (var i = 0; i < fallingMemes.length; i++) {
			var meme = fallingMemes[i];
			if (meme.memeType === self.memeType && meme.y > lowestY) {
				lowestY = meme.y;
				matchedMeme = meme;
			}
		}
		// If a match was found
		if (matchedMeme) {
			// Remove the matched meme from the active array immediately so it can't be matched again
			var index = fallingMemes.indexOf(matchedMeme);
			if (index > -1) {
				fallingMemes.splice(index, 1);
			}
			// Animate the meme fading out
			tween(matchedMeme, {
				alpha: 0
			}, {
				duration: 300,
				// 300ms fade duration
				easing: tween.easeOut,
				// Use an easing function
				onFinish: function onFinish() {
					// Destroy the game object *after* the animation completes
					if (matchedMeme && matchedMeme.destroy) {
						// Check if it wasn't already destroyed elsewhere
						matchedMeme.destroy();
					}
				}
			});
			// Increase score and update display
			var currentScore = LK.getScore() + 1;
			LK.setScore(currentScore);
			scoreTxt.setText(currentScore);
			// Check if a score milestone of 50 has been reached
			var currentMilestone = Math.floor(currentScore / 50) * 50;
			if (currentMilestone > lastScoreMilestone && currentMilestone > 0) {
				gameSpeed += 1;
				lastScoreMilestone = currentMilestone;
				console.log("Speed increased to: " + gameSpeed); // Optional: log speed increase
			}
			// --- Reveal new buttons based on score ---
			var targetVisibleButtons = 4 + Math.floor(currentScore / 20);
			while (visibleButtonCount < targetVisibleButtons && visibleButtonCount < buttons.length) {
				var nextButton = buttons[visibleButtonCount];
				if (nextButton) {
					// Check if the button exists
					nextButton.visible = true;
					// Optional: Add a small visual effect when a button appears
					// nextButton.alpha = 0;
					// tween(nextButton, { alpha: 1 }, { duration: 200 });
				}
				// --- Spawn the newly revealed meme immediately ---
				var newlyRevealedButton = buttons[visibleButtonCount];
				if (newlyRevealedButton) {
					// Create a new falling meme instance for the revealed type
					var newMeme = new FallingMeme(newlyRevealedButton.memeType, gameSpeed);
					var assetWidth = newMeme.assetWidth;
					newMeme.x = Math.random() * (GAME_WIDTH - assetWidth) + assetWidth / 2;
					newMeme.y = -newMeme.assetHeight / 2;
					newMeme.lastY = newMeme.y;
					game.addChild(newMeme);
					fallingMemes.push(newMeme);
				}
				// --- End Immediate Spawn Logic ---
				visibleButtonCount++;
			}
			// --- End Reveal Logic ---
			// Construct the specific sound ID for this meme type
			var specificSoundId = self.memeType + 'matchsound1';
			// Play the specific match sound
			LK.getSound(specificSoundId).play();
			// Optional: Add a visual feedback like flashing the button
			LK.effects.flashObject(self, 0x800080, 200); // Flash purple briefly
		} else {
			// Optional: Handle incorrect tap (e.g., small screen flash red, sound)
			// LK.effects.flashScreen(0xFF0000, 100);
			// LK.getSound('missSound').play(); // Potentially confusing with game over sound
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x111111 // Dark grey background
});
/**** 
* Game Code
****/ 
// Game constants and variables
// Initialize assets used in this game. Engine will automatically create if not present.
// Assuming square meme images. Adjust width/height if needed.
// Define 20 meme assets with placeholder shapes and colors
// Red
// Lime
// Blue
// Yellow
// Magenta
// Cyan
// Orange
// Purple
// Green
// Maroon
// Navy
// Olive
// Teal
// Silver
// Gray
// Khaki
// Lavender
// PeachPuff
// LightBlue
// LightGreen
// Import tween plugin for animations
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var MEME_TYPES = ['meme1', 'meme2', 'meme3', 'meme4', 'meme5', 'meme6', 'meme7', 'meme8', 'meme9', 'meme10', 'meme11', 'meme12', 'meme13', 'meme14', 'meme15', 'meme16', 'meme17', 'meme18', 'meme19', 'meme20'];
var INITIAL_SPEED = 5;
var SPAWN_INTERVAL_TICKS = 90; // How often to spawn a new meme (90 ticks = 1.5 seconds at 60fps)
var fallingMemes = []; // Array to hold active FallingMeme instances
var scoreTxt;
var gameSpeed = INITIAL_SPEED;
var spawnCounter = 0;
var lastScoreMilestone = 0; // Track the last score milestone for speed increase
var visibleButtonCount = 4; // Start with the first 4 buttons visible
// --- Game state variables ---
var gameStarted = false;
var introBackground;
var gameBackground;
var startButton;
// --- Intro Background ---
introBackground = game.attachAsset('Background1', {
	anchorX: 0.5,
	anchorY: 0.5
});
// Scale the intro background
introBackground.scaleX = GAME_WIDTH / introBackground.width;
introBackground.scaleY = GAME_HEIGHT / introBackground.height;
introBackground.x = GAME_WIDTH / 2;
introBackground.y = GAME_HEIGHT / 2;
// --- Game Background (initially hidden) ---
gameBackground = game.attachAsset('Background0', {
	anchorX: 0.5,
	anchorY: 0.5
});
// Scale the game background
gameBackground.scaleX = GAME_WIDTH / gameBackground.width;
gameBackground.scaleY = GAME_HEIGHT / gameBackground.height;
gameBackground.x = GAME_WIDTH / 2;
gameBackground.y = GAME_HEIGHT / 2;
gameBackground.visible = false;
// --- Start Button ---
startButton = game.attachAsset('Startbutton', {
	anchorX: 0.5,
	anchorY: 0.5
});
startButton.x = GAME_WIDTH / 2;
startButton.y = GAME_HEIGHT / 2 + 800;
// --- Highscore Button ---
var highscoreButton = game.attachAsset('Highscorebutton', {
	anchorX: 0.5,
	anchorY: 0.5
});
highscoreButton.x = GAME_WIDTH / 2;
highscoreButton.y = GAME_HEIGHT / 2 + 1070;
highscoreButton.interactive = true;
// Add a back button to return to intro from high score screen
var backButton = new Text2('Back to Intro', {
	size: 80,
	fill: 0xFFFFFF
});
backButton.anchor.set(0.5, 0.5);
backButton.x = GAME_WIDTH / 2;
backButton.y = GAME_HEIGHT - 200;
backButton.visible = false;
backButton.interactive = true;
// Add a close button in the top right corner for the high score screen
var closeButton = game.attachAsset('Closebutton', {
	anchorX: 0.5,
	anchorY: 0.5
});
closeButton.x = GAME_WIDTH - 100; // Position in top right, 100px from edge
closeButton.y = 100; // Position 100px from top
closeButton.visible = false;
closeButton.interactive = true;
backButton.down = function () {
	// Hide high score elements
	if (game.highScoreContainer) {
		game.highScoreContainer.visible = false;
	}
	if (game.background2) {
		game.background2.visible = false;
	}
	backButton.visible = false;
	closeButton.visible = false; // Hide close button too
	// Show intro elements
	introBackground.visible = true;
	startButton.visible = true;
	highscoreButton.visible = true;
};
// Close button has the same functionality as back button
closeButton.down = function () {
	// Hide high score elements
	if (game.highScoreContainer) {
		game.highScoreContainer.visible = false;
	}
	if (game.background2) {
		game.background2.visible = false;
	}
	backButton.visible = false;
	closeButton.visible = false;
	// Show intro elements
	introBackground.visible = true;
	startButton.visible = true;
	highscoreButton.visible = true;
};
game.addChild(backButton);
game.addChild(closeButton);
// Update highscore button to show back button
highscoreButton.down = function () {
	LK.effects.flashObject(highscoreButton, 0xFF0000, 300);
	// Hide current background and show background2
	introBackground.visible = false;
	gameBackground.visible = false;
	startButton.visible = false;
	highscoreButton.visible = false;
	backButton.visible = true;
	closeButton.visible = true; // Show close button when entering high score screen
	// Create and show background2 if it doesn't exist yet
	if (!game.background2) {
		game.background2 = game.attachAsset('Background2', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Scale the background2
		game.background2.scaleX = GAME_WIDTH / game.background2.width;
		game.background2.scaleY = GAME_HEIGHT / game.background2.height;
		game.background2.x = GAME_WIDTH / 2;
		game.background2.y = GAME_HEIGHT / 2;
	} else {
		game.background2.visible = true;
	}
	// Create and show high score container if it doesn't exist yet
	if (!game.highScoreContainer) {
		game.highScoreContainer = new Container();
		game.addChild(game.highScoreContainer);
		game.highScoreContainer.x = GAME_WIDTH / 2;
		game.highScoreContainer.y = 300;
	}
	game.highScoreContainer.visible = true;
	// Display current high score using stored value
	var highScore = storage.highScore || 0;
	var currentMessage = "Your High Score: " + highScore;
	// Add new score text below previous ones
	var scoreText = new Text2(currentMessage, {
		size: 80,
		fill: 0xFFFFFF
	});
	scoreText.anchor.set(0.5, 0);
	scoreText.y = game.highScoreContainer.children.length * 100;
	game.highScoreContainer.addChild(scoreText);
};
highscoreButton.down = function () {
	LK.effects.flashObject(highscoreButton, 0xFF0000, 300);
	// Hide current background and show background2
	introBackground.visible = false;
	gameBackground.visible = false;
	startButton.visible = false;
	highscoreButton.visible = false;
	backButton.visible = true;
	closeButton.visible = true; // Show close button when entering high score screen
	// Create and show background2 if it doesn't exist yet
	if (!game.background2) {
		game.background2 = game.attachAsset('Background2', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Scale the background2
		game.background2.scaleX = GAME_WIDTH / game.background2.width;
		game.background2.scaleY = GAME_HEIGHT / game.background2.height;
		game.background2.x = GAME_WIDTH / 2;
		game.background2.y = GAME_HEIGHT / 2;
		// Make sure closeButton is in front of background2
		game.removeChild(closeButton);
		game.addChild(closeButton);
	} else {
		game.background2.visible = true;
		// Make sure closeButton is in front of background2
		game.removeChild(closeButton);
		game.addChild(closeButton);
	}
	// Create and show high score container if it doesn't exist yet
	if (!game.highScoreContainer) {
		game.highScoreContainer = new Container();
		game.addChild(game.highScoreContainer);
		game.highScoreContainer.x = GAME_WIDTH / 2;
		game.highScoreContainer.y = 300;
	} else {
		// Clear previous scores
		while (game.highScoreContainer.children.length > 0) {
			game.highScoreContainer.removeChild(game.highScoreContainer.children[0]);
		}
	}
	game.highScoreContainer.visible = true;
	// Access storage properties directly, not using get method
	var accountId = storage.accountId;
	var highScore = 0;
	var playerScores = [];
	// Create title text
	var titleText = new Text2("High Scores", {
		size: 100,
		fill: 0xFFFFFF
	});
	titleText.anchor.set(0.5, 0);
	titleText.y = 0;
	game.highScoreContainer.addChild(titleText);
	// Collect all scores with player names
	if (accountId) {
		// Access storage property directly for current account ID
		highScore = storage['highScore_' + accountId] || 0;
		var playerName = storage['playerName_' + accountId] || "You";
		playerScores.push({
			score: highScore,
			name: playerName
		});
		// Check if there are other stored scores
		for (var key in storage) {
			if (key.startsWith('highScore_') && key !== 'highScore_' + accountId) {
				var otherAccountId = key.substring(10); // Remove 'highScore_'
				var otherName = storage['playerName_' + otherAccountId] || "Player";
				playerScores.push({
					score: storage[key],
					name: otherName
				});
			}
		}
	} else {
		// Fallback to legacy storage
		highScore = storage.highScore || 0;
		playerScores.push({
			score: highScore,
			name: "You"
		});
	}
	// Sort scores in descending order
	playerScores.sort(function (a, b) {
		return b.score - a.score;
	});
	// Display scores from highest to lowest
	for (var i = 0; i < playerScores.length; i++) {
		var playerScore = playerScores[i];
		var scoreText = new Text2(playerScore.name + ": " + playerScore.score, {
			size: 80,
			fill: 0xFFFFFF
		});
		scoreText.anchor.set(0.5, 0);
		scoreText.y = 120 + i * 100;
		game.highScoreContainer.addChild(scoreText);
	}
};
// --- Score Display ---
scoreTxt = new Text2('0', {
	size: 120,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0); // Anchor top-center
// Position score text at the top-center using LK.gui
LK.gui.top.addChild(scoreTxt);
// Offset slightly down to avoid interfering with potential top-bar elements
scoreTxt.y = 20;
// Hide score until game starts
scoreTxt.visible = false;
// --- Meme Buttons ---
// Generate random size between 200 and 600 for memes
function getRandomMemeSize() {
	return Math.floor(Math.random() * 401) + 200; // Random between 200 and 600
}
// --- Helper function to spawn a single meme ---
function spawnMeme(availableTypes) {
	var randomIndex = Math.floor(Math.random() * availableTypes.length);
	var newMemeType = availableTypes[randomIndex];
	// Create a new falling meme instance
	var newMeme = new FallingMeme(newMemeType, gameSpeed);
	// Apply random size to the meme
	var randomSize = getRandomMemeSize();
	newMeme.scale.set(randomSize / 200); // Scale based on original 200px size
	// Position it randomly across the top, avoiding edges slightly
	var scaledWidth = newMeme.assetWidth * newMeme.scale.x; // Calculate scaled width
	newMeme.x = Math.random() * (GAME_WIDTH - scaledWidth) + scaledWidth / 2;
	newMeme.y = -newMeme.assetHeight * newMeme.scale.y / 2; // Start just above the screen
	// Initialize last state tracking
	newMeme.lastY = newMeme.y;
	// Add to game stage and tracking array
	game.addChild(newMeme);
	fallingMemes.push(newMeme);
}
// --- Helper function to spawn two memes of the same type side-by-side ---
function spawnDoubleMeme(memeType) {
	// Create a dummy instance to get dimensions (assuming all memes of a type have same dims)
	var tempMeme = new FallingMeme(memeType, 0); // Speed doesn't matter here
	var assetWidth = tempMeme.assetWidth;
	var assetHeight = tempMeme.assetHeight;
	tempMeme.destroy(); // Clean up the temporary meme
	// Generate random sizes for both memes
	var randomSize1 = getRandomMemeSize();
	var randomSize2 = getRandomMemeSize();
	var scale1 = randomSize1 / 200;
	var scale2 = randomSize2 / 200;
	// Calculate scaled dimensions
	var scaledWidth1 = assetWidth * scale1;
	var scaledWidth2 = assetWidth * scale2;
	var scaledHeight1 = assetHeight * scale1;
	var scaledHeight2 = assetHeight * scale2;
	var spacing = Math.max(scaledWidth1, scaledWidth2) + 20; // Width of the wider meme plus a small gap
	// Calculate the valid range for the center of the *left* meme (x1)
	var minX1 = scaledWidth1 / 2;
	var maxX1 = GAME_WIDTH - scaledWidth2 / 2 - spacing;
	// If the memes + spacing are wider than the screen, this calculation might result in minX1 > maxX1.
	if (minX1 > maxX1) {
		minX1 = scaledWidth1 / 2;
		maxX1 = GAME_WIDTH - scaledWidth2 / 2 - spacing; // Recalculate maxX1 based on the actual space needed
		// If still invalid, clamp
		if (minX1 > maxX1) {
			maxX1 = minX1;
		}
	}
	var x1 = Math.random() * (maxX1 - minX1) + minX1;
	var x2 = x1 + spacing;
	// Create the first meme with random size
	var meme1 = new FallingMeme(memeType, gameSpeed);
	meme1.scale.set(scale1);
	meme1.x = x1;
	meme1.y = -scaledHeight1 / 2;
	meme1.lastY = meme1.y;
	game.addChild(meme1);
	fallingMemes.push(meme1);
	// Create the second meme with random size
	var meme2 = new FallingMeme(memeType, gameSpeed);
	meme2.scale.set(scale2);
	meme2.x = x2;
	meme2.y = -scaledHeight2 / 2; // Start at the same height
	meme2.lastY = meme2.y;
	game.addChild(meme2);
	fallingMemes.push(meme2);
}
var buttons = [];
var buttonPadding = 5; // Reduced padding as buttons are larger
var buttonsPerRow = 10;
var buttonRows = 2;
var buttonAssetWidth = 200; // Set directly as we know the asset size
var buttonAssetHeight = 200; // Set directly as we know the asset size
// Create buttons first
for (var i = 0; i < MEME_TYPES.length; i++) {
	var memeType = MEME_TYPES[i];
	var button = new MemeButton(memeType);
	buttons.push(button);
	// No need to get dimensions here anymore, set statically above
}
// Calculate layout based on button dimensions and padding
var totalWidthForRow = buttonAssetWidth * buttonsPerRow + buttonPadding * (buttonsPerRow - 1);
var startX = (GAME_WIDTH - totalWidthForRow) / 2;
var rowSpacing = buttonAssetHeight + 30; // Vertical space between rows
var bottomRowY = GAME_HEIGHT - buttonAssetHeight / 2 - 50; // Position bottom row near the screen bottom
var topRowY = bottomRowY - rowSpacing;
// Position and add buttons in two rows
for (var i = 0; i < buttons.length; i++) {
	var button = buttons[i];
	var rowIndex = Math.floor(i / buttonsPerRow); // 0 for first row, 1 for second
	var colIndex = i % buttonsPerRow; // 0 to 9 for column in the row
	var currentX = startX + colIndex * (buttonAssetWidth + buttonPadding);
	button.x = currentX + button.assetWidth / 2; // Position based on center anchor
	if (rowIndex === 0) {
		button.y = topRowY;
	} else {
		button.y = bottomRowY;
	}
	// Hide all buttons initially until the game starts
	button.visible = false;
	game.addChild(button);
}
// --- Game Update Logic ---
game.update = function () {
	// Only run game logic if the game has started
	if (!gameStarted) {
		// No need to do anything else when in the intro screen
		// The button rotation animation is handled by tweens
		return;
	}
	spawnCounter++;
	// Spawn new memes periodically
	if (spawnCounter >= SPAWN_INTERVAL_TICKS) {
		spawnCounter = 0;
		// --- Select a meme type from the *visible* buttons ---
		var visibleMemeTypes = [];
		for (var k = 0; k < visibleButtonCount; k++) {
			if (buttons[k]) {
				// Ensure the button exists
				visibleMemeTypes.push(buttons[k].memeType);
			}
		}
		// Only spawn if there are visible types to choose from
		if (visibleMemeTypes.length > 0) {
			if (visibleButtonCount === MEME_TYPES.length) {
				// All buttons visible: Spawn a pair of the *same* meme type
				var randomIndex = Math.floor(Math.random() * visibleMemeTypes.length);
				var chosenMemeType = visibleMemeTypes[randomIndex];
				spawnDoubleMeme(chosenMemeType);
			} else {
				// Not all buttons visible: Spawn a single random meme from the visible types
				spawnMeme(visibleMemeTypes);
			}
		}
		// --- End Spawn Logic Modification ---
		// Gradually increase difficulty (optional)
		// gameSpeed += 0.05;
		// SPAWN_INTERVAL_TICKS = Math.max(30, SPAWN_INTERVAL_TICKS * 0.995); // Decrease spawn interval slowly
	}
	// Update and check existing falling memes
	for (var i = fallingMemes.length - 1; i >= 0; i--) {
		var meme = fallingMemes[i];
		// Update last position before moving
		if (meme.lastY === undefined) {
			meme.lastY = meme.y;
		} // Initialize if needed
		// Check if meme reached the bottom (transition detection)
		// Check if the bottom edge of the meme crosses the button line
		// Account for scaling when calculating bottom edge
		var bottomEdge = meme.y + meme.assetHeight * meme.scale.y / 2;
		var lastBottomEdge = meme.lastY + meme.assetHeight * meme.scale.y / 2;
		var boundaryY = bottomRowY - buttonAssetHeight / 2 - 20; // Line slightly above the *lower* row of buttons
		if (lastBottomEdge <= boundaryY && bottomEdge > boundaryY) {
			// Meme crossed the line - Game Over
			LK.getSound('missSound').play(); // Play miss sound
			// Save high score with account ID before game over
			var currentScore = LK.getScore();
			var accountId = storage.accountId;
			if (accountId) {
				// Save score with account ID by directly setting storage property
				storage['highScore_' + accountId] = Math.max(storage['highScore_' + accountId] || 0, currentScore);
				// Also save player name if available
				if (!storage['playerName_' + accountId]) {
					storage['playerName_' + accountId] = storage.playerName || "Player";
				}
			} else {
				// Fallback for users without account ID
				storage.highScore = Math.max(storage.highScore || 0, currentScore);
			}
			LK.showGameOver(); // Trigger game over handled by LK engine
			// Important: showGameOver stops further execution of this game instance
			return; // Exit update loop as game is ending
		}
		// If it somehow got way past the screen (cleanup, although game over should trigger first)
		if (meme.isOffScreen(GAME_HEIGHT + 100)) {
			// This case should ideally not be reached due to game over check above
			meme.destroy();
			fallingMemes.splice(i, 1);
		}
		// Update last known states
		meme.lastY = meme.y;
	}
};
// Set up start button press event handler
startButton.interactive = true;
startButton.down = function () {
	// Start the game when button is pressed
	gameStarted = true;
	// Hide intro elements
	introBackground.visible = false;
	startButton.visible = false;
	// Show game elements
	gameBackground.visible = true;
	// Show buttons
	for (var i = 0; i < visibleButtonCount; i++) {
		if (buttons[i]) {
			buttons[i].visible = true;
		}
	}
	// Reset score if needed
	LK.setScore(0);
	scoreTxt.setText("0");
};
// Note: Button presses for memes are handled by the MemeButton class's down method.;
// Play intro music when the game loads
LK.playMusic('Intromusic1');
// Start continuous button rotation animation
function animateButtonRotation() {
	// Rotate to -10 degrees first (convert to radians)
	tween(startButton, {
		rotation: -10 * (Math.PI / 180)
	}, {
		duration: 800,
		easing: tween.easeInOut,
		onFinish: function onFinish() {
			// Then rotate to 0 degrees
			tween(startButton, {
				rotation: 0
			}, {
				duration: 800,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					// Then rotate to 10 degrees
					tween(startButton, {
						rotation: 10 * (Math.PI / 180)
					}, {
						duration: 800,
						easing: tween.easeInOut,
						onFinish: function onFinish() {
							// Then back to 0 degrees
							tween(startButton, {
								rotation: 0
							}, {
								duration: 800,
								easing: tween.easeInOut,
								onFinish: animateButtonRotation // Loop the animation
							});
						}
					});
				}
			});
		}
	});
}
// Start the animation
animateButtonRotation();
// When the game starts, switch to game music
startButton.down = function () {
	// Flash the start button red when clicked
	LK.effects.flashObject(startButton, 0xFF0000, 300);
	// Start the game when button is pressed
	gameStarted = true;
	// Hide intro elements
	introBackground.visible = false;
	startButton.visible = false;
	highscoreButton.visible = false; // Hide highscore button when game starts
	// Hide high score container and background2 if visible
	if (game.highScoreContainer) {
		game.highScoreContainer.visible = false;
	}
	if (game.background2) {
		game.background2.visible = false;
	}
	// Stop any ongoing button rotation animation
	tween.stop(startButton, {
		rotation: true
	});
	// Show game elements
	gameBackground.visible = true;
	// Show buttons
	for (var i = 0; i < visibleButtonCount; i++) {
		if (buttons[i]) {
			buttons[i].visible = true;
		}
	}
	// Reset score if needed
	LK.setScore(0);
	scoreTxt.setText("0");
	// Make score visible now that game has started
	scoreTxt.visible = true;
	// Switch to game music when the game starts
	LK.playMusic('Gamemusic1');
}; ===================================================================
--- original.js
+++ change.js
@@ -367,40 +367,53 @@
 	game.highScoreContainer.visible = true;
 	// Access storage properties directly, not using get method
 	var accountId = storage.accountId;
 	var highScore = 0;
-	var allScores = [];
+	var playerScores = [];
 	// Create title text
 	var titleText = new Text2("High Scores", {
 		size: 100,
 		fill: 0xFFFFFF
 	});
 	titleText.anchor.set(0.5, 0);
 	titleText.y = 0;
 	game.highScoreContainer.addChild(titleText);
-	// Collect all scores
+	// Collect all scores with player names
 	if (accountId) {
 		// Access storage property directly for current account ID
 		highScore = storage['highScore_' + accountId] || 0;
-		allScores.push(highScore);
+		var playerName = storage['playerName_' + accountId] || "You";
+		playerScores.push({
+			score: highScore,
+			name: playerName
+		});
 		// Check if there are other stored scores
 		for (var key in storage) {
 			if (key.startsWith('highScore_') && key !== 'highScore_' + accountId) {
-				allScores.push(storage[key]);
+				var otherAccountId = key.substring(10); // Remove 'highScore_'
+				var otherName = storage['playerName_' + otherAccountId] || "Player";
+				playerScores.push({
+					score: storage[key],
+					name: otherName
+				});
 			}
 		}
 	} else {
 		// Fallback to legacy storage
 		highScore = storage.highScore || 0;
-		allScores.push(highScore);
+		playerScores.push({
+			score: highScore,
+			name: "You"
+		});
 	}
 	// Sort scores in descending order
-	allScores.sort(function (a, b) {
-		return b - a;
+	playerScores.sort(function (a, b) {
+		return b.score - a.score;
 	});
 	// Display scores from highest to lowest
-	for (var i = 0; i < allScores.length; i++) {
-		var scoreText = new Text2((i === 0 ? "Highest Score: " : "Score: ") + allScores[i], {
+	for (var i = 0; i < playerScores.length; i++) {
+		var playerScore = playerScores[i];
+		var scoreText = new Text2(playerScore.name + ": " + playerScore.score, {
 			size: 80,
 			fill: 0xFFFFFF
 		});
 		scoreText.anchor.set(0.5, 0);
@@ -586,8 +599,12 @@
 			var accountId = storage.accountId;
 			if (accountId) {
 				// Save score with account ID by directly setting storage property
 				storage['highScore_' + accountId] = Math.max(storage['highScore_' + accountId] || 0, currentScore);
+				// Also save player name if available
+				if (!storage['playerName_' + accountId]) {
+					storage['playerName_' + accountId] = storage.playerName || "Player";
+				}
 			} else {
 				// Fallback for users without account ID
 				storage.highScore = Math.max(storage.highScore || 0, currentScore);
 			}
 Same face in the image but 3D
 3D Scary trollface meme. In-Game asset. 3D. High contrast. No shadows
 3D jeff the killer Scary face meme. In-Game asset. 3D. High contrast. No shadows
 3D Scary face meme "Terrifier3" from the movie, face only In-Game asset. 3D. High contrast. No shadows. face only
 3D Scary but funny annabelle doll face meme. In-Game asset. 3D. High contrast. No shadows
 
 3D Scary but funny meme face of momo. face only. different faces look In-Game asset. 3d. High contrast. No shadows
 
 
 
 
 
 
 
 
 
 
 
 
 
 3D Scary room with many 3D decorations around, 3D scary masks of memes from movies around it. In-Game asset. 3D. High contrast. No shadows. no jesus cross. no star of 6. no start of 5. no devil. HD colors
 3D Scary room with many 3D decorations around, 3D scary masks of memes from movies around it. In-Game asset. 3D. High contrast. No shadows. no jesus cross. no star of 6. no start of 5. no devil. HD colors
 3D Scary face meme samara and angry. only face. normal eyes not so opened. In-Game asset. High contrast. 3D. No shadows. only face
 
 Gamemusic1
Music
meme1matchsound1
Sound effect
meme2matchsound1
Sound effect
meme3matchsound1
Sound effect
meme4matchsound1
Sound effect
meme5matchsound1
Sound effect
meme6matchsound1
Sound effect
meme7matchsound1
Sound effect
meme8matchsound1
Sound effect
meme9matchsound1
Sound effect
meme10matchsound1
Sound effect
meme11matchsound1
Sound effect
meme12matchsound1
Sound effect
meme13matchsound1
Sound effect
meme14matchsound1
Sound effect
meme15matchsound1
Sound effect
meme16matchsound1
Sound effect
meme17matchsound1
Sound effect
meme18matchsound1
Sound effect
meme19matchsound1
Sound effect
meme20matchsound1
Sound effect
missSound
Sound effect
Intromusic1
Music