User prompt
Update wave system as needed with: targetPitch = normalizedPitch * 0.4 + lastPitch * 0.6; // More weight on previous pitch lastPitch += (targetPitch - lastPitch) * 0.15; // Slower rise speed
Code edit (1 edits merged)
Please save this source code
User prompt
Update surfer as needed with: function showScorePopup(points, trickType) { var message = trickType === 'spin' ? "SPIN!" : "FRONT FLIP!"; var scorePopup = new Text2(message + "\n+" + points, { size: 150, fill: 0xFFFFFF, align: 'center', weight: 800 }); scorePopup.anchor.set(0.5, 0.5); scorePopup.x = 2048 / 2; // Calculate Y position based on active popups var baseY = 2732 / 2 - 200; var offset = activePopups.length * 200; // Each popup shifts up by 200 scorePopup.y = baseY - offset; game.addChild(scorePopup); activePopups.push(scorePopup); scorePopup.scale.set(0.1); tween(scorePopup.scale, { x: 1.2, y: 1.2 }, { duration: 400, easing: tween.elasticOut, onFinish: function onFinish() { tween(scorePopup, { alpha: 0, y: scorePopup.y - 200 }, { duration: 1000, delay: 800, easing: tween.easeOut, onFinish: function onFinish() { var index = activePopups.indexOf(scorePopup); if (index > -1) { activePopups.splice(index, 1); } scorePopup.destroy(); } }); } }); } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (2 edits merged)
Please save this source code
User prompt
Update wave system self.update as needed with: var targetPitch = 0; // Reset everything if pitch is null/undefined (face lost) if (facekit.pitch === null || facekit.pitch === undefined) { targetPitch = 0; lastPitch = 0; smoothedHeight = 0; } else if (facekit.volume > 0.5) { var normalizedPitch = (facekit.pitch - MIN_PITCH) / (MAX_PITCH - MIN_PITCH); normalizedPitch = Math.max(0, Math.min(1, normalizedPitch)); targetPitch = normalizedPitch * 0.6 + lastPitch * 0.4; } lastPitch += (targetPitch - lastPitch) * 0.2; ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Update wave system as needed with: var targetPitch = 0; if (facekit.volume > 0.5) { var normalizedPitch = (facekit.pitch - MIN_PITCH) / (MAX_PITCH - MIN_PITCH); normalizedPitch = Math.max(0, Math.min(1, normalizedPitch)); targetPitch = normalizedPitch * 0.6 + lastPitch * 0.4; lastPitch += (targetPitch - lastPitch) * 0.2; } else { lastPitch *= 0.95; // Gradually return to base level when no input } ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Update wave system with: var targetPitch = 0; if (facekit.volume > 0.5 && facekit.isTracking) { // Changed to isTracking var normalizedPitch = (facekit.pitch - MIN_PITCH) / (MAX_PITCH - MIN_PITCH); normalizedPitch = Math.max(0, Math.min(1, normalizedPitch)); targetPitch = normalizedPitch * 0.6 + lastPitch * 0.4; } else { targetPitch = 0; lastPitch = 0; } ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Update wave system with: var targetPitch = 0; if (facekit.volume > 0.5 && facekit.faceDetected) { // Add faceDetected check var normalizedPitch = (facekit.pitch - MIN_PITCH) / (MAX_PITCH - MIN_PITCH); normalizedPitch = Math.max(0, Math.min(1, normalizedPitch)); targetPitch = normalizedPitch * 0.6 + lastPitch * 0.4; } else { // When face is not detected, gradually return to base level lastPitch *= 0.95; // Smooth descent } ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: MIN_VOLUME_FOR_SPIN' in or related to this line: 'if (currentRotationState === ROTATION_STATES.NORMAL && !self.isJumping && facekit.volume > MIN_VOLUME_FOR_SPIN && canSpin) {' Line Number: 607
Code edit (1 edits merged)
Please save this source code
User prompt
Update surfer with: var waveRideTime = 0; var TIME_FOR_SPIN = 300; var spinRotation = 0; var SPIN_STATE = 'spinning'; var SPIN_SPEED = 0.15; var canSpin = true;
User prompt
Update surfer as needed with: self.update = function() { if (!waveSystem) return; // Handle ongoing spin if (currentRotationState === SPIN_STATE) { spinRotation += SPIN_SPEED; self.scale.x = Math.cos(spinRotation); if (spinRotation >= Math.PI * 2) { currentRotationState = ROTATION_STATES.NORMAL; self.scale.x = 1; spinRotation = 0; score += 1000; showScorePopup(1000, 'spin'); waveRideTime = 0; canSpin = false; LK.setTimeout(function() { canSpin = true; }, 2000); } // Wave riding timer - ONLY way to trigger spins now } else if (currentRotationState === ROTATION_STATES.NORMAL && !self.isJumping && !aboveWave && canSpin) { waveRideTime++; if (waveRideTime >= TIME_FOR_SPIN) { currentRotationState = SPIN_STATE; spinRotation = 0; waveRideTime = 0; } } else { waveRideTime = 0; } // Rest of update logic... };
Code edit (1 edits merged)
Please save this source code
User prompt
Update surfer as needed with: // In Surfer update if (currentRotationState === ROTATION_STATES.NORMAL && !self.isJumping && !aboveWave && // Make sure we're on the wave Math.abs(self.y - currentWaveY) < WAVE_TOLERANCE) { // Actually riding it waveRideTime++; if (waveRideTime >= TIME_FOR_SPIN && canSpin) { currentRotationState = SPIN_STATE; spinRotation = 0; waveRideTime = 0; } } else { // Reset timer for ANY disruption waveRideTime = 0; }
Code edit (1 edits merged)
Please save this source code
User prompt
Update surfer with: // In the FLIPPING state landing logic, fix flip scoring check: if (groundContact && !lastGroundContact) { landingCount++; console.log('Landing initiated:', landingCount); currentRotationState = ROTATION_STATES.RECOVERING; self.y = currentWaveY; velocityY = 0; // Only award points if we completed close to a full rotation var completedFlips = Math.abs(rotationData.totalRotation) / (Math.PI * 2); console.log('Rotation amount:', completedFlips); if (completedFlips > 0.8) { // Must complete at least 80% of a flip score += 1000; showScorePopup(1000, 'flip'); } rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); }
User prompt
Update surfer as needed with: // At top of Surfer class with other variables var waveRideTime = 0; var TIME_FOR_SPIN = 180; // 3 seconds at 60fps var canSpin = true; var spinRotation = 0; var SPIN_STATE = 'spinning'; var SPIN_SPEED = 0.15; // In the update function self.update = function() { if (!waveSystem) return; // Handle ongoing spin if (currentRotationState === SPIN_STATE) { spinRotation += SPIN_SPEED; self.scale.x = Math.cos(spinRotation); if (spinRotation >= Math.PI * 2) { currentRotationState = ROTATION_STATES.NORMAL; self.scale.x = 1; spinRotation = 0; score += 1000; showScorePopup(1000, 'spin'); // Reset wave ride timer after spin waveRideTime = 0; // Add cooldown before next spin can be earned canSpin = false; LK.setTimeout(function() { canSpin = true; }, 2000); // 2 second cooldown } } // Track wave riding time and trigger spin if (!self.isJumping && currentRotationState === ROTATION_STATES.NORMAL) { // Only increment timer if we're past initial game start (add small delay) if (LK.ticks > 60) { // Wait 1 second before starting to count waveRideTime++; if (waveRideTime >= TIME_FOR_SPIN && canSpin) { console.log('Earned spin from wave riding!'); currentRotationState = SPIN_STATE; spinRotation = 0; waveRideTime = 0; } } } else { // Reset timer if we jump or do other tricks waveRideTime = 0; } // Rest of update code... };
User prompt
Update surfer as needed with: // Add near top of Surfer class with other variables var waveRideTime = 0; var TIME_FOR_SPIN = 180; // 3 seconds at 60fps var canSpin = true; var spinRotation = 0; var SPIN_STATE = 'spinning'; var SPIN_SPEED = 0.15; // In the update function, modify the wave riding tracking and spin trigger self.update = function() { if (!waveSystem) return; // Handle ongoing spin if (currentRotationState === SPIN_STATE) { spinRotation += SPIN_SPEED; self.scale.x = Math.cos(spinRotation); if (spinRotation >= Math.PI * 2) { currentRotationState = ROTATION_STATES.NORMAL; self.scale.x = 1; spinRotation = 0; canSpin = false; score += 1000; showScorePopup(1000, 'spin'); // Reset wave ride timer after spin waveRideTime = 0; } } // Track wave riding time and trigger spin if (!self.isJumping && currentRotationState === ROTATION_STATES.NORMAL) { waveRideTime++; // Give spin after sustained riding if (waveRideTime >= TIME_FOR_SPIN && canSpin) { console.log('Earned spin from wave riding!'); currentRotationState = SPIN_STATE; spinRotation = 0; waveRideTime = 0; // Reset timer } } else { // Reset timer if we jump or do other tricks waveRideTime = 0; } // Rest of update code... };
User prompt
Please fix the bug: 'TypeError: console.trace is not a function. (In 'console.trace('Score popup called with:', points, trickType)', 'console.trace' is undefined)' in or related to this line: 'console.trace('Score popup called with:', points, trickType);' Line Number: 405
User prompt
Update surfer as needed: if (groundContact && !lastGroundContact) { score += 1000; showScorePopup(1000, 'flip'); // ... rest of flip completion code }
User prompt
Update surfer as needed with: // For spin: if (spinRotation >= Math.PI * 2) { currentRotationState = ROTATION_STATES.NORMAL; self.scale.x = 1; spinRotation = 0; canSpin = false; score += 1000; showScorePopup(1000, 'spin'); // ... rest of spin completion code }
User prompt
Update surfer as needed with: function showScorePopup(points, trickType) { console.trace('Score popup called with:', points, trickType); var message = trickType === 'spin' ? "SPIN!" : "FRONT FLIP!"; var scorePopup = new Text2(message + "\n+" + points, { size: 150, fill: 0xFFFFFF, align: 'center', weight: 800 }); // ... rest of popup code }
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	bestScore: 0
});
var facekit = LK.import("@upit/facekit.v1");
/**** 
* Classes
****/ 
// Define BASE_Y constant
var Cloud = Container.expand(function () {
	var self = Container.call(this);
	var cloudAlpha = 0.5 + Math.random() * 0.4; // Random alpha between 0.5 and 0.9
	var cloudGraphics = self.attachAsset('cloud', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: cloudAlpha
	});
	cloudGraphics.scale.set(cloudAlpha, cloudAlpha); // Scale based on alpha
	// Initialize cloud position
	self.x = 2248; // Start off-screen right
	self.y = Math.random() * (2732 * 0.33); // Top third of screen
	self.speed = -2 - Math.random() * 2; // Random speed variation
	self.update = function () {
		self.x += self.speed;
		// Remove if off screen
		if (self.x < -self.width) {
			self.destroy();
		}
	};
	return self;
});
var Fish = Container.expand(function () {
	var self = Container.call(this);
	var fishGraphics = self.attachAsset('fish', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var randomScale = 0.5 + Math.random(); // Random scale between 0.5 and 1.5
	fishGraphics.scale.set(randomScale, randomScale);
	self.speed = -3 - Math.random() * 2; // Slower than seagulls
	self.y = 2732 * (0.87 + Math.random() * 0.1); // Position between 87-97% of screen height
	self.x = 2248; // Start off-screen right
	// Use simple sine wave for animation instead of tweens
	self.baseY = self.y;
	self.startTime = LK.ticks;
	self.update = function () {
		self.x += self.speed;
		// Smooth swimming motion using sine wave
		self.y = self.baseY + Math.sin((LK.ticks - self.startTime) * 0.05) * 15;
		fishGraphics.rotation = Math.sin((LK.ticks - self.startTime) * 0.1) * 0.1;
		// Remove if off screen
		if (self.x < -100) {
			self.destroy();
		}
	};
	return self;
});
var ParticleSystem = Container.expand(function () {
	var self = Container.call(this);
	self.addWaterParticle = function (x, y, type) {
		var particle = ParticlePool.get();
		if (type === 'trail') {
			// Move spawn point up and behind surfer
			particle.x = x - 100; // Spawn behind (to the right of) surfer
			particle.y = y + 10; // Raised up from previous +90
		} else {
			// Keep original splash positioning
			particle.x = x + Math.random() * 130 - 40;
			particle.y = y - 20;
		}
		particle.init(type);
		self.addChild(particle);
	};
	self.update = function () {
		for (var i = self.children.length - 1; i >= 0; i--) {
			var particle = self.children[i];
			if (particle.update) {
				particle.update();
			}
			// Remove particles that have moved far off screen
			if (particle.x < -500 || particle.x > 2548 || particle.y < -500 || particle.y > 3232) {
				ParticlePool["return"](particle);
				self.removeChild(particle);
			}
		}
	};
	return self;
});
var Rock = Container.expand(function () {
	var self = Container.call(this);
	var rock = self.attachAsset('island', {
		anchorX: 0.5,
		anchorY: 1 // Anchor to top since we're stretching upward
	});
	// Set scales independently
	rock.scaleX = 2;
	rock.scaleY = 2; // Start with a base scale
	self.checkCollision = function (surfer) {
		var rockWidth = self.width;
		var rockHeight = self.height;
		var rockTop = self.y - rockHeight;
		var points = [{
			x: self.x,
			y: rockTop
		}, {
			x: self.x - rockWidth * 0.4,
			y: self.y - rockHeight * 0.1
		}, {
			x: self.x + rockWidth * 0.4,
			y: self.y - rockHeight * 0.1
		}];
		var surferBox = {
			x: surfer.x - 30,
			y: surfer.y - 30,
			width: 60,
			height: 60
		};
		return isPointInTriangle(surferBox.x, surferBox.y, points) || isPointInTriangle(surferBox.x + surferBox.width, surferBox.y, points) || isPointInTriangle(surferBox.x, surferBox.y + surferBox.height, points) || isPointInTriangle(surferBox.x + surferBox.width, surferBox.y + surferBox.height, points);
	};
	self.update = function () {
		if (self.lastX === undefined) {
			self.lastX = self.x;
		} // Initialize lastX if not set
		self.x -= 8;
		if (self.x < -self.width) {
			self.destroy();
		}
		self.lastX = self.x; // Update lastX
	};
	return self;
});
var Seagull = Container.expand(function () {
	var self = Container.call(this);
	var seagullGraphics = self.attachAsset('seagull', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Circle collision data
	self.radius = 150; // Increase the collision radius for larger detection
	self.collisionX = 0;
	self.collisionY = 0;
	self.speed = -5 - Math.random() * 3; // Random speed variation
	self.y = Math.random() * (2732 * 0.33); // Top third of screen
	self.x = 2248; // Start off-screen right
	// Flying animation
	function flyAnimation() {
		tween(self, {
			y: self.y + (Math.random() * 100 - 50)
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: flyAnimation
		});
		// Wing flap effect
		tween(seagullGraphics, {
			scaleY: 0.8,
			y: 5
		}, {
			duration: 500,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(seagullGraphics, {
					scaleY: 1,
					y: 0
				}, {
					duration: 500,
					easing: tween.easeInOut
				});
			}
		});
	}
	flyAnimation();
	self.update = function () {
		self.x += self.speed;
		// Update collision circle position
		self.collisionX = self.x;
		self.collisionY = self.y;
		// Remove if off screen
		if (self.x < -100) {
			self.destroy();
		}
		// Circle collision with surfer
		var dx = self.collisionX - surfer.x;
		var dy = self.collisionY - surfer.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance < self.radius + 40) {
			// 40 is approximate surfer radius
			LK.showGameOver();
		}
	};
	return self;
});
var Shark = Container.expand(function () {
	var self = Container.call(this);
	var sharkGraphics = self.attachAsset('shark', {
		anchorX: 0.5,
		anchorY: 0.2
	});
	self.radius = 50;
	self.collisionX = 0;
	self.collisionY = 0;
	// Constants
	var SWIM_SPEED = 7;
	var CHASE_SPEED = 12;
	var ESCAPE_SPEED = 15;
	var DETECTION_RANGE = 800;
	var CRUISE_HEIGHT = 2732 * 0.85;
	var MIN_CHASE_TIME = 60; // 1 second at 60fps
	var GRAVITY = 0.8;
	var MAX_FALL_SPEED = 20;
	self.chaseTimer = 0;
	self.speed = SWIM_SPEED;
	self.state = 'cruising';
	self.targetRotation = 0;
	self.velocityY = 0;
	self.y = CRUISE_HEIGHT;
	function swim() {
		tween(sharkGraphics, {
			scaleX: 1.1
		}, {
			duration: 500,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(sharkGraphics, {
					scaleX: 0.9
				}, {
					duration: 500,
					easing: tween.easeInOut,
					onFinish: swim
				});
			}
		});
	}
	swim();
	self.update = function () {
		// Get wave height at current position for collision
		var normalizedX = self.x / 2048;
		var pointIndex = Math.floor(normalizedX * (waveSystem.points.length - 1));
		var nextPointIndex = Math.min(pointIndex + 1, waveSystem.points.length - 1);
		if (pointIndex >= 0 && pointIndex < waveSystem.points.length) {
			var currentPoint = waveSystem.points[pointIndex];
			var nextPoint = waveSystem.points[nextPointIndex];
			var progress = normalizedX * (waveSystem.points.length - 1) - pointIndex;
			var waveY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress;
			var dx = surfer.x - self.x;
			var dy = surfer.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			// Only apply gravity if we're above the wave
			if (self.y < waveY) {
				// In air, apply gravity
				self.velocityY += GRAVITY;
				self.velocityY = Math.min(self.velocityY, MAX_FALL_SPEED);
				self.y += self.velocityY;
			} else {
				// Return to cruise height when in water, BUT NOT DURING CHASE
				if (self.state !== 'chasing' && self.state !== 'escaping') {
					self.y = CRUISE_HEIGHT;
					self.velocityY = 0;
				}
			}
			switch (self.state) {
				case 'cruising':
					self.speed = SWIM_SPEED;
					self.targetRotation = 0;
					// Only chase if shark is to the right of surfer and within height/distance
					if (distance < DETECTION_RANGE && surfer.y > self.y - 500 && self.x > surfer.x) {
						// Increased from 300
						self.state = 'chasing';
						self.chaseTimer = 0;
					}
					break;
				case 'chasing':
					self.speed = CHASE_SPEED;
					// Only rotate toward player if shark hasn't passed them
					if (self.x > surfer.x) {
						self.targetRotation = -Math.atan2(surfer.y - self.y, self.x - surfer.x) * 0.3;
					} else {
						self.targetRotation = 0;
					}
					self.chaseTimer++;
					// Increased movement factor for more aggressive vertical chase
					if (self.y > waveY) {
						// Only move up if in water
						var targetY = Math.max(surfer.y, CRUISE_HEIGHT - 400);
						self.y += (targetY - self.y) * 0.1; // Increased from 0.05 to 0.1
					}
					// Only escape if minimum chase time has elapsed AND escape conditions are met
					if (self.chaseTimer > MIN_CHASE_TIME && (surfer.y < self.y - 600 || self.x < surfer.x - 100)) {
						self.state = 'escaping';
						self.targetRotation = 0;
					}
					break;
				case 'escaping':
					self.speed = ESCAPE_SPEED;
					self.y += 10;
					self.targetRotation = 0;
					break;
			}
			// Smooth rotation
			self.rotation += (self.targetRotation - self.rotation) * 0.1;
		}
		// Move based on current speed
		self.x -= self.speed;
		// Update collision
		self.collisionX = self.x;
		self.collisionY = self.y + 20;
		// Check collision with surfer
		var collisionDx = self.collisionX - surfer.x;
		var collisionDy = self.collisionY - surfer.y;
		var collisionDistance = Math.sqrt(collisionDx * collisionDx + collisionDy * collisionDy);
		if (collisionDistance < self.radius + 40) {
			LK.showGameOver();
		}
		if (self.x < -200 || self.y > CRUISE_HEIGHT + 400) {
			self.destroy();
		}
	};
	return self;
});
var Surfer = Container.expand(function () {
	var self = Container.call(this);
	// State management
	var currentWaveY = 0; // Add this at class level
	var isLanding = false;
	var landingCount = 0; // Debug counter to see multiple transitions
	var landingStartRotation = 0;
	var groundContact = false;
	var lastGroundContact = false;
	var BASE_GRAVITY = 1.2; // Reduced gravity for more hang time
	var DAMPENING = 0.99; // Less dampening for more momentum
	var JUMP_BOOST = 1.5; // Multiplier for upward velocity
	var MIN_AIR_TIME_FOR_FLIP = 30; // Frames before allowing flip
	var MIN_ROTATION_SPEED = 0.13; // Base rotation speed
	var ROTATION_BASE_SPEED = 0.10; // Slowed down from previous value
	var MAX_ROTATION_SPEED = 0.18; // Reduced max speed
	var WAVE_OFFSET = -30;
	var FIXED_X = 2048 * 0.35;
	var MAX_AIR_VELOCITY = 25; // Changed to positive since we're falling
	var WAVE_TOLERANCE = 2; // Tighter tolerance
	var SPLASH_VELOCITY_THRESHOLD = 15; // Minimum velocity for splash
	var TRICK_HEIGHT_THRESHOLD = 50; // Lower threshold for testing
	var initialJumpY = 0; // Track height where we left the wave
	var wasAboveWave = false; // Add this to track state change
	// State management
	var ROTATION_STATES = {
		NORMAL: 'normal',
		FLIPPING: 'flipping',
		RECOVERING: 'recovering'
	};
	var currentRotationState = ROTATION_STATES.NORMAL;
	var waveRideTime = 0;
	var TIME_FOR_SPIN = 240;
	var spinRotation = 0;
	var SPIN_STATE = 'spinning';
	var SPIN_SPEED = 0.15;
	var canSpin = true;
	var rotationData = {
		baseRotation: -0.1,
		trickRotation: 0,
		totalRotation: 0,
		recoveryTarget: 0
	};
	// Physics variables
	var velocityY = 0;
	var lastWaveY = 2732 * 0.85;
	var initialized = false;
	var activePopups = [];
	// Setup surfer graphics
	var surferGraphics = self.attachAsset('surfer', {
		anchorX: 0.5,
		anchorY: 0.8
	});
	// Initial position
	self.x = FIXED_X;
	self.y = lastWaveY + WAVE_OFFSET;
	// Helper functions
	function normalizeRotation(rotation) {
		return rotation % (Math.PI * 2);
	}
	function showScorePopup(points, trickType) {
		console.log('Score popup called with:', points, trickType);
		var message = trickType === 'spin' ? "SPIN!" : "FRONT FLIP!";
		var scorePopup = new Text2(message + "\n+" + points, {
			size: 150,
			fill: 0xFFFFFF,
			align: 'center',
			weight: 800
		});
		scorePopup.anchor.set(0.5, 0.5);
		scorePopup.x = 2048 / 2; // Center of screen horizontally 
		scorePopup.y = 2732 / 2 - 200; // Center of screen vertically, slightly up 
		game.addChild(scorePopup);
		scorePopup.scale.set(0.1);
		tween(scorePopup.scale, {
			x: 1.2,
			y: 1.2
		}, {
			duration: 400,
			easing: tween.elasticOut,
			onFinish: function onFinish() {
				tween(scorePopup, {
					alpha: 0,
					y: scorePopup.y - 200
				}, {
					duration: 1000,
					delay: 800,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						scorePopup.destroy();
					}
				});
			}
		});
	}
	function createSplash() {
		for (var i = 0; i < 50; i++) {
			game.particles.addWaterParticle(FIXED_X, self.y + 40, 'splash');
		}
	}
	function createTrail() {
		for (var i = 0; i < 4; i++) {
			game.particles.addWaterParticle(FIXED_X, self.y, 'trail');
		}
	}
	function updateRotation(aboveWave) {
		// Debug log outside switch to see all values
		if (aboveWave) {
			console.log('State:', currentRotationState, 'VelocityY:', velocityY, 'Height diff:', initialJumpY - self.y);
		}
		// Handle jump height tracking outside of state machine
		if (aboveWave && !wasAboveWave) {
			initialJumpY = self.y;
		} else if (!aboveWave) {
			initialJumpY = 0;
		}
		// Track ground contact changes
		lastGroundContact = groundContact;
		groundContact = !aboveWave;
		// Debug our state transitions
		if (LK.ticks % 10 === 0) {
			console.log('State:', currentRotationState, 'Ground:', groundContact, 'LastGround:', lastGroundContact);
		}
		// Debug logs
		if (currentRotationState === ROTATION_STATES.RECOVERING || currentRotationState === ROTATION_STATES.FLIPPING) {
			console.log('Frame:', LK.ticks, 'State:', currentRotationState, 'Above:', aboveWave, 'VelocityY:', velocityY, 'Landing Count:', landingCount);
		}
		switch (currentRotationState) {
			case ROTATION_STATES.NORMAL:
				isLanding = false;
				wasAboveWave = aboveWave;
				// Only start tracking initial height when first leaving wave
				if (aboveWave && !wasAboveWave) {
					initialJumpY = self.y;
					airTime = 0; // Reset air time counter
				} else if (aboveWave) {
					airTime++; // Increment while in air
				} else {
					airTime = 0;
					initialJumpY = 0;
				}
				// Only enter flip if we've been in air long enough
				if (aboveWave && velocityY > 10 && airTime > MIN_AIR_TIME_FOR_FLIP) {
					console.log('Starting new trick sequence, air time:', airTime);
					currentRotationState = ROTATION_STATES.FLIPPING;
					rotationData.trickRotation = self.rotation;
					landingCount = 0;
				} else {
					var waveRotation = Math.sin(LK.ticks / 30) * 0.05;
					var verticalSpeed = self.y - lastWaveY;
					var verticalRotation = 0;
					if (Math.abs(verticalSpeed) > 5) {
						if (verticalSpeed < -2) {
							verticalRotation = Math.min(0.2, -verticalSpeed * 0.003);
						} else if (verticalSpeed > 2) {
							verticalRotation = Math.max(-0.3, -verticalSpeed * 0.003);
						}
					}
					var targetRotation = rotationData.baseRotation + waveRotation + verticalRotation;
					var lerpSpeed = currentRotationState === ROTATION_STATES.RECOVERING ? 0.05 : 0.1;
					self.rotation += (targetRotation - self.rotation) * lerpSpeed;
				}
				break;
			case ROTATION_STATES.FLIPPING:
				// Calculate rotation speed based on initial upward velocity
				var velocityFactor = Math.min(Math.abs(velocityY) / 20, 1); // Normalize velocity
				var rotationSpeed = ROTATION_BASE_SPEED + (MAX_ROTATION_SPEED - ROTATION_BASE_SPEED) * velocityFactor;
				rotationData.trickRotation += rotationSpeed;
				rotationData.totalRotation += rotationSpeed;
				self.rotation = rotationData.trickRotation;
				// Only transition to recovering on first ground contact
				if (groundContact && !lastGroundContact && currentRotationState === ROTATION_STATES.FLIPPING) {
					landingCount++;
					console.log('Landing initiated:', landingCount);
					currentRotationState = ROTATION_STATES.RECOVERING;
					self.y = currentWaveY;
					velocityY = 0;
					// Only award points if we completed close to a full rotation
					var completedFlips = Math.abs(rotationData.totalRotation) / (Math.PI * 2);
					console.log('Rotation amount:', completedFlips);
					if (completedFlips > 0.8) {
						// Must complete at least 80% of a flip
						score += 1000;
						showScorePopup(1000, 'flip');
					}
					rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation);
					createSplash();
				}
				break;
			case ROTATION_STATES.RECOVERING:
				var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation);
				var recoverySpeed = 0.15; // Increased from 0.1
				var recoveryThreshold = 0.03; // Increased from 0.01
				// Add dampening
				rotationData.recoveryVelocity = (rotationData.recoveryVelocity || 0) * 0.8;
				rotationData.recoveryVelocity += diff * recoverySpeed;
				self.rotation += rotationData.recoveryVelocity;
				if (groundContact && currentRotationState === ROTATION_STATES.RECOVERING) {
					self.y += (currentWaveY - self.y) * 0.2; // Smooth transition to wave
					velocityY *= 0.8; // Gradual velocity reduction
				}
				if (Math.abs(diff) < recoveryThreshold && Math.abs(rotationData.recoveryVelocity) < 0.01 && groundContact) {
					console.log('Recovery complete, landing count:', landingCount);
					currentRotationState = ROTATION_STATES.NORMAL;
					rotationData.trickRotation = 0;
					rotationData.totalRotation = 0;
					landingCount = 0; // Reset counter
					self.y = currentWaveY; // Use currentWaveY here too
					velocityY = 0;
					rotationData.trickRotation = 0;
					rotationData.totalRotation = 0;
				} else {
					self.rotation += rotationData.recoveryVelocity;
				}
				break;
		}
	}
	// Wave system setup
	self.setWaveSystem = function (ws) {
		waveSystem = ws;
		if (!waveSystem.points) {
			waveSystem.points = [];
		}
		initialized = true;
	};
	// Main update function
	self.update = function () {
		if (!waveSystem) {
			return;
		}
		// Handle ongoing spin
		if (currentRotationState === SPIN_STATE) {
			spinRotation += SPIN_SPEED;
			self.scale.x = Math.cos(spinRotation);
			if (spinRotation >= Math.PI * 2) {
				currentRotationState = ROTATION_STATES.NORMAL;
				self.scale.x = 1;
				spinRotation = 0;
				score += 1000;
				showScorePopup(1000, 'spin');
				waveRideTime = 0;
				canSpin = false;
				LK.setTimeout(function () {
					canSpin = true;
				}, 2000);
			}
		} else if (currentRotationState === ROTATION_STATES.NORMAL && !self.isJumping && !aboveWave && canSpin) {
			waveRideTime++;
			if (waveRideTime >= TIME_FOR_SPIN) {
				currentRotationState = SPIN_STATE;
				spinRotation = 0;
				waveRideTime = 0;
			}
		} else {
			waveRideTime = 0;
		}
		var normalizedX = self.x / 2048;
		var pointIndex = Math.floor(normalizedX * (waveSystem.points.length - 1));
		var nextPointIndex = Math.min(pointIndex + 1, waveSystem.points.length - 1);
		var progress = normalizedX * (waveSystem.points.length - 1) - pointIndex;
		var currentPoint = waveSystem.points[pointIndex];
		var nextPoint = waveSystem.points[nextPointIndex];
		if (!currentPoint || !nextPoint) {
			return;
		}
		var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress + WAVE_OFFSET;
		currentWaveY = targetY; // Store for use in updateRotation
		// Add tolerance zone for wave contact
		var aboveWave = self.y < targetY;
		// Add tolerance zone for wave contact
		var inWaterContact = Math.abs(self.y - targetY) <= WAVE_TOLERANCE;
		// Simpler above wave check
		if (aboveWave) {
			airTime++;
			// If we're going up, boost the velocity
			if (velocityY < 0) {
				velocityY *= JUMP_BOOST;
			}
			velocityY += BASE_GRAVITY;
			velocityY *= DAMPENING;
			// Debug log
			if (LK.ticks % 10 === 0) {
				console.log('Air time:', airTime, 'VelocityY:', velocityY, 'Height:', self.y);
			}
		} else {
			airTime = 0;
			self.y = targetY;
			velocityY *= 0.8;
		}
		// Update position
		self.y += velocityY;
		// Update rotation state
		updateRotation(aboveWave);
		// More controlled particle triggers
		if (inWaterContact) {
			createTrail();
			// Only create splash on hard impacts
			if (velocityY > SPLASH_VELOCITY_THRESHOLD) {
				createSplash();
			}
		}
		lastWaveY = targetY;
	};
	self.getScore = function () {
		return Math.floor(score);
	};
	return self;
});
var WaterParticle = Container.expand(function () {
	var self = Container.call(this);
	var particleGraphics = self.attachAsset('wave_point', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var speed, angle, scale;
	self.init = function (type) {
		// Reset properties
		scale = 1;
		self.type = type;
		if (type === 'trail') {
			speed = Math.random() * 8 + 6;
			angle = Math.PI + (Math.random() * 0.4 - 0.2);
			scale = 0.7;
			particleGraphics.alpha = 0.8;
		} else {
			speed = Math.random() * 12 + 8;
			angle = -Math.PI / 2 + (Math.random() * 1.4 - 0.7);
			scale = 1.2;
			particleGraphics.alpha = 0.9;
		}
		self.scale.set(scale, scale);
	};
	self.update = function () {
		scale -= self.type === 'splash' ? 0.04 : 0.02;
		self.scale.set(scale, scale);
		if (scale <= 0) {
			// Instead of destroying, return to pool
			if (self.parent) {
				self.parent.removeChild(self);
			}
			ParticlePool["return"](self);
			return;
		}
		self.x += Math.cos(angle) * speed;
		self.y += Math.sin(angle) * speed;
	};
	return self;
});
var WaveSystem = Container.expand(function () {
	var self = Container.call(this);
	var NUM_POINTS = 40;
	var SCREEN_WIDTH = 2048;
	var points = [];
	var baseY = 2732 * 0.85;
	var MIN_PITCH = 60;
	var MAX_PITCH = 400;
	var calibrationSamples = [];
	self.isCalibrating = true;
	var CALIBRATION_SAMPLES = 100; // Doubled to 100 samples 
	var CALIBRATION_VOLUME_THRESHOLD = 0.5; // Minimum volume to count as valid input 
	var calibrationStartTime = LK.ticks;
	var CALIBRATION_TIMEOUT = 300; // 5 seconds (60 ticks per second)
	var WAVE_HEIGHT = 2000;
	var lastPitch = 0;
	// Create calibration message
	var background = LK.getAsset('background', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.alpha = 0.7;
	background.scale.set(10, 2); // Adjust scale as needed
	// Add background first so it's behind the text
	LK.gui.center.addChild(background);
	var calibrationText = new Text2("Make some noise!\nHum high and low to calibrate", {
		size: 60,
		fill: 0xFFFFFF,
		align: 'center'
	});
	calibrationText.anchor.set(0.5, 0.5);
	LK.gui.center.addChild(calibrationText);
	// Progress indicator
	var progressText = new Text2("0%", {
		size: 40,
		fill: 0xFFFFFF,
		alpha: 0.8
	});
	progressText.anchor.set(0.5, 0.5);
	progressText.y = calibrationText.y + 80;
	LK.gui.center.addChild(progressText);
	// Removed visual pitch indicator and labels
	function updatePitchRange(pitch) {
		if (facekit.volume > CALIBRATION_VOLUME_THRESHOLD) {
			calibrationSamples.push(pitch);
			// Update progress display 
			var progress = Math.min(100, Math.floor(calibrationSamples.length / CALIBRATION_SAMPLES * 100));
			progressText.setText(progress + "%");
			// Removed pitch indicator position update as visual indicator is no longer used
			if (calibrationSamples.length >= CALIBRATION_SAMPLES) {
				finishCalibration();
			}
		}
		// Check for timeout 
		if (LK.ticks - calibrationStartTime > CALIBRATION_TIMEOUT) {
			if (calibrationSamples.length < 10) {
				// Not enough samples 
				// Reset and extend time 
				calibrationSamples = [];
				calibrationStartTime = LK.ticks;
				calibrationText.setText("Let's try again!\nMake some noise - hum or speak");
			} else {
				finishCalibration(); // Use what we have 
			}
		}
	}
	function finishCalibration() {
		var sortedPitches = calibrationSamples.sort(function (a, b) {
			return a - b;
		});
		MIN_PITCH = sortedPitches[Math.floor(calibrationSamples.length * 0.1)];
		MAX_PITCH = sortedPitches[Math.floor(calibrationSamples.length * 0.9)];
		// Add padding to range 
		MIN_PITCH = Math.max(30, MIN_PITCH - 10);
		MAX_PITCH = MAX_PITCH + 20;
		self.isCalibrating = false;
		// Show completion message 
		calibrationText.setText("Ready!");
		background.destroy();
		calibrationText.destroy();
		progressText.destroy();
		// Fade out completion message 
		tween(calibrationText, {
			alpha: 0
		}, {
			duration: 1000,
			onFinish: function onFinish() {
				return calibrationText.destroy();
			}
		});
		// Removed pitch meter cleanup
		console.log("Calibrated pitch range:", MIN_PITCH, "to", MAX_PITCH);
	}
	// Enhanced smoothing system
	var heightBuffer = Array(30).fill(0);
	var bufferIndex = 0;
	var lastSmoothedHeight = 0;
	// Water fill rectangles
	var waterRects = [];
	var NUM_WATER_SECTIONS = 80; // Reduced from 80 
	for (var i = 0; i < NUM_WATER_SECTIONS; i++) {
		var rect = self.attachAsset('wave_line', {
			anchorX: 0.5,
			// Center anchor
			anchorY: 0,
			// Top anchor
			height: 2732,
			width: SCREEN_WIDTH / NUM_WATER_SECTIONS + 1,
			// Tiny overlap to prevent pixel gaps
			tint: 0x0066cc,
			alpha: 0.3
		});
		waterRects.push(rect);
	}
	// Create wave line segments
	var lines = [];
	function createLines() {
		// Clean up any existing lines first
		lines.forEach(function (line) {
			line.destroy();
			self.removeChild(line);
		});
		lines = [];
		// Create new lines
		for (var i = 0; i < NUM_POINTS - 1; i++) {
			var line = self.attachAsset('wave_line', {
				anchorX: 0,
				anchorY: 0.5,
				height: 4
			});
			lines.push(line);
		}
	}
	// Call initial creation
	createLines();
	function gaussianCurve(x) {
		return Math.exp(-(x * x) / 0.8);
	}
	function getSmoothedHeight(newHeight) {
		heightBuffer[bufferIndex] = newHeight;
		bufferIndex = (bufferIndex + 1) % heightBuffer.length;
		// Simplified smoothing calculation
		var total = 0;
		var weights = 0;
		for (var i = 0; i < heightBuffer.length; i++) {
			var weight = Math.pow(0.95, i); // Exponential decay
			total += heightBuffer[(bufferIndex - i + heightBuffer.length) % heightBuffer.length] * weight;
			weights += weight;
		}
		var smoothedHeight = total / weights;
		lastSmoothedHeight = lastSmoothedHeight * 0.85 + smoothedHeight * 0.15; // Changed from 0.7/0.3
		return lastSmoothedHeight;
	}
	self.update = function () {
		// Always calculate wave points first, regardless of calibration state
		var targetPitch = 0;
		if (facekit.volume > 0.5) {
			var normalizedPitch = (facekit.pitch - MIN_PITCH) / (MAX_PITCH - MIN_PITCH);
			normalizedPitch = Math.max(0, Math.min(1, normalizedPitch));
			targetPitch = normalizedPitch * 0.6 + lastPitch * 0.4;
		}
		lastPitch += (targetPitch - lastPitch) * 0.2;
		var smoothedHeight = getSmoothedHeight(lastPitch * WAVE_HEIGHT);
		points = [];
		for (var i = 0; i < NUM_POINTS; i++) {
			var x = i / (NUM_POINTS - 1) * SCREEN_WIDTH;
			var distanceFromCenter = (x - SCREEN_WIDTH * 0.35) / (SCREEN_WIDTH * 0.45);
			var heightFactor = gaussianCurve(distanceFromCenter);
			var y = baseY - smoothedHeight * heightFactor;
			points.push({
				x: x,
				y: y
			});
		}
		// Always update water rectangles
		for (var i = 0; i < NUM_WATER_SECTIONS; i++) {
			var rect = waterRects[i];
			var xPosition = i / NUM_WATER_SECTIONS * SCREEN_WIDTH;
			var exactPointPosition = xPosition / SCREEN_WIDTH * (NUM_POINTS - 1);
			var pointIndex = Math.floor(exactPointPosition);
			var nextPointIndex = Math.min(pointIndex + 1, NUM_POINTS - 1);
			var progress = exactPointPosition - pointIndex;
			var y1 = points[pointIndex].y;
			var y2 = points[nextPointIndex].y;
			var y = y1 + (y2 - y1) * progress;
			rect.x = xPosition;
			rect.y = y;
			rect.height = 2732 - y;
			rect.alpha = 0.3 + Math.sin(LK.ticks * 0.02 + i * 0.2) * 0.02;
		}
		self.points = points;
		// Handle calibration if still calibrating
		if (self.isCalibrating) {
			if (facekit.volume > CALIBRATION_VOLUME_THRESHOLD) {
				calibrationSamples.push(facekit.pitch);
				var progress = Math.min(100, Math.floor(calibrationSamples.length / CALIBRATION_SAMPLES * 100));
				progressText.setText(progress + "%");
				if (calibrationSamples.length >= CALIBRATION_SAMPLES) {
					finishCalibration();
				}
			}
			if (LK.ticks - calibrationStartTime > CALIBRATION_TIMEOUT) {
				if (calibrationSamples.length < 10) {
					calibrationSamples = [];
					calibrationStartTime = LK.ticks;
					calibrationText.setText("Let's try again!\nMake some noise - hum or speak");
				} else {
					finishCalibration();
				}
			}
		} else {
			// Only update score when not calibrating
			if (facekit.volume > 0.5) {
				score += smoothedHeight / WAVE_HEIGHT * multiplier;
				multiplier += 0.001;
			} else {
				multiplier = Math.max(1, multiplier - 0.01);
			}
		}
		// Always update wave line segments
		for (var i = 0; i < lines.length; i++) {
			var start = points[i];
			var end = points[i + 1];
			var dx = end.x - start.x;
			var dy = end.y - start.y;
			var length = Math.sqrt(dx * dx + dy * dy);
			var angle = Math.atan2(dy, dx);
			lines[i].x += (start.x - lines[i].x) * 0.3;
			lines[i].y += (start.y - lines[i].y) * 0.3;
			lines[i].width += (length - lines[i].width) * 0.3;
			var angleDiff = angle - lines[i].rotation;
			if (angleDiff > Math.PI) {
				angleDiff -= Math.PI * 2;
			}
			if (angleDiff < -Math.PI) {
				angleDiff += Math.PI * 2;
			}
			lines[i].rotation += angleDiff * 0.3;
		}
	};
	self.destroy = function () {
		waterRects.forEach(function (rect) {
			return rect.destroy();
		});
		lines.forEach(function (line) {
			return line.destroy();
		});
		waterRects = [];
		lines = [];
		Container.prototype.destroy.call(this);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 //Init game with black background 
});
/**** 
* Game Code
****/ 
var BASE_Y = 2732 * 0.85;
var ParticlePool = {
	pool: [],
	maxSize: 200,
	get: function get() {
		if (this.pool.length > 0) {
			var particle = this.pool.pop();
			particle.visible = true;
			return particle;
		}
		return new WaterParticle();
	},
	"return": function _return(particle) {
		if (this.pool.length < this.maxSize) {
			// Reset particle properties
			particle.visible = false;
			particle.scale.set(1, 1);
			particle.x = 0;
			particle.y = 0;
			particle.rotation = 0;
			this.pool.push(particle);
		} else {
			particle.destroy();
		}
	}
};
function isPointInTriangle(px, py, points) {
	var p0 = points[0],
		p1 = points[1],
		p2 = points[2];
	var A = 1 / 2 * (-p1.y * p2.x + p0.y * (-p1.x + p2.x) + p0.x * (p1.y - p2.y) + p1.x * p2.y);
	var sign = A < 0 ? -1 : 1;
	var s = (p0.y * p2.x - p0.x * p2.y + (p2.y - p0.y) * px + (p0.x - p2.x) * py) * sign;
	var t = (p0.x * p1.y - p0.y * p1.x + (p0.y - p1.y) * px + (p1.x - p0.x) * py) * sign;
	return s > 0 && t > 0 && s + t < 2 * A * sign;
}
var lastScoreDisplay = -1;
var lastMultiplierDisplay = -1;
var originalSetInterval = LK.setInterval;
LK.setInterval = function () {
	for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
		args[_key] = arguments[_key];
	}
	var timer = originalSetInterval.apply(this, args);
	gameTimers.push(timer);
	return timer;
};
var originalSetTimeout = LK.setTimeout;
LK.setTimeout = function () {
	for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
		args[_key2] = arguments[_key2];
	}
	var timer = originalSetTimeout.apply(this, args);
	gameTimers.push(timer);
	return timer;
};
var gameTimers = [];
// Set an interval to play the waves sound effect every 4-6 seconds
var wavesSoundInterval = LK.setInterval(function () {
	LK.getSound('waves').play();
}, 4000 + Math.random() * 2000); // Random interval between 4-6 seconds
gameTimers.push(wavesSoundInterval);
var seagullSpawnInterval = 6000; // Spawn every 3 seconds
var lastSeagullSpawn = 0;
var lastCloudSpawn = 0;
var cloudSpawnInterval = 1000 + Math.random() * 2000; // Random interval between 1-3 seconds
function spawnSeagull() {
	if (Date.now() - lastSeagullSpawn > seagullSpawnInterval) {
		var seagull = new Seagull();
		game.addChild(seagull);
		LK.getSound('seagull').play(); // Play seagull sound effect
		lastSeagullSpawn = Date.now();
		seagullSpawnInterval = 3000 + Math.random() * 3000; // Random interval between 1-3 seconds 
	}
}
var rocks = [];
var lastRockTime = 0;
var fishSpawnInterval = 8000;
var lastFishSpawn = 0;
var lastSharkSpawn = Date.now() + 8000;
var sharkSpawnInterval = 8000; // Initial spawn interval (8 seconds)
var lastWholeMultiplier = 1;
var score = 0; // Initialize score variable
var multiplier = 1;
var lastWaveHeight = 0;
var lastWaveUpdate = 0;
var devicePerformance = 1; // Default performance multiplier
var poseidon = LK.getAsset('poseidon', {
	anchorX: 0.5,
	anchorY: 0.5
});
game.addChild(poseidon);
var mouth = LK.getAsset('mouth', {
	anchorX: 0.5,
	// Center anchor
	anchorY: 0.5,
	// Center anchor
	alpha: 0 // Initialize alpha to 0
});
game.addChild(mouth);
var waveSystem = game.addChild(new WaveSystem());
var particles = new ParticleSystem();
game.particles = game.addChild(new ParticleSystem());
var surfer = game.addChild(new Surfer());
surfer.setWaveSystem(waveSystem);
var scoreText = new Text2("", {
	size: 100,
	fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var multiplierText = new Text2("", {
	size: 60,
	fill: 0xFFFFFF,
	alpha: 0.8
});
multiplierText.anchor.set(1, 1);
LK.gui.bottomRight.addChild(multiplierText);
var bestScoreText = new Text2("Best: " + storage.bestScore, {
	size: 60,
	fill: 0xFFFFFF,
	alpha: 0.8
});
bestScoreText.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(bestScoreText);
// Game update function
var lastUpdateTime = 0;
game.update = function () {
	var now = Date.now();
	if (now - lastUpdateTime < 16) {
		// Don't update faster than 60fps
		return;
	}
	lastUpdateTime = now;
	// Every 300 frames, log counts
	if (LK.ticks % 600 === 0) {
		console.log('Active timers:', gameTimers.length);
	}
	if (LK.ticks % 300 === 0) {
		console.log('Particle count:', game.particles.children.length);
		console.log('Wave points:', waveSystem.points.length);
		console.log('Total game children:', game.children.length);
		console.log('Active tweens:', tween.getActiveTweens ? tween.getActiveTweens().length : 0);
	}
	waveSystem.update();
	surfer.update();
	particles.update();
	// Update Poseidon's position to follow the player's face 
	if (facekit.noseTip) {
		poseidon.x = facekit.noseTip.x;
		poseidon.y = facekit.noseTip.y;
	}
	// Update mouth position to follow the player's mouth 
	if (facekit.mouthCenter) {
		mouth.x = facekit.mouthCenter.x;
		mouth.y = facekit.mouthCenter.y + 90;
		if (facekit.volume > 0.45) {
			// Change alpha to 1 when volume is greater than 0.35
			mouth.alpha = 1;
		} else {
			mouth.alpha = 0;
		}
	}
	// Only spawn obstacles if not calibrating
	if (!waveSystem.isCalibrating) {
		// Rock spawning
		if (LK.ticks - lastRockTime > 240 + Math.random() * 360) {
			lastRockTime = LK.ticks;
			var rock = game.addChild(new Rock());
			rock.x = 2548; // Start off right side
			rock.y = 2732 + 200; // Place base below screen
			// Set the vertical scale independently for random height
			rock.children[0].scaleY = 3 + Math.random() * 4; // Random height between 3x and 7x
			rocks.push(rock);
		}
		if (!waveSystem.isCalibrating && Date.now() - lastSharkSpawn > sharkSpawnInterval) {
			var shark = new Shark();
			shark.x = 2548;
			var spawnPointIndex = waveSystem.points.length - 1;
			var waveY = waveSystem.points[spawnPointIndex].y;
			shark.y = waveY + 60;
			game.addChild(shark);
			lastSharkSpawn = Date.now();
			sharkSpawnInterval = 8000 + Math.random() * 8000;
		}
		// Seagull spawning
		spawnSeagull();
	}
	// Cloud spawning
	if (Date.now() - lastCloudSpawn > cloudSpawnInterval) {
		var cloud = new Cloud();
		game.addChildAt(cloud, game.getChildIndex(poseidon) + (Math.random() < 0.5 ? 0 : 1)); // Add cloud at Poseidon's layer or one above
		lastCloudSpawn = Date.now();
		cloudSpawnInterval = 2000 + Math.random() * 2000; // Random interval between 2-4 seconds 
	}
	if (Date.now() - lastFishSpawn > fishSpawnInterval) {
		var fish = new Fish();
		game.addChild(fish);
		lastFishSpawn = Date.now();
		fishSpawnInterval = 3000 + Math.random() * 3000; // Random interval between 3-6 seconds
	}
	// Update and check rocks
	for (var i = rocks.length - 1; i >= 0; i--) {
		var rock = rocks[i];
		rock.update();
		// Remove destroyed rocks
		if (!rock.parent) {
			rocks.splice(i, 1);
			continue;
		}
		// Check collision with surfer
		if (rock.checkCollision(surfer)) {
			LK.showGameOver();
		}
	}
	game.children.forEach(function (child) {
		if (child instanceof Seagull && child.update) {
			child.update();
		}
	});
	var currentScore = Math.floor(score);
	if (currentScore !== lastScoreDisplay) {
		lastScoreDisplay = currentScore;
		scoreText.setText(currentScore.toLocaleString());
	}
	if (currentScore > storage.bestScore) {
		storage.bestScore = currentScore;
		bestScoreText.setText("Best: " + storage.bestScore);
	}
	var currentMultiplier = Math.floor(multiplier * 10) / 10; // Round to 1 decimal
	if (currentMultiplier !== lastMultiplierDisplay) {
		lastMultiplierDisplay = currentMultiplier;
		multiplierText.setText("x" + currentMultiplier.toFixed(1));
	}
	var currentWholeMultiplier = Math.floor(multiplier);
	if (currentWholeMultiplier > lastWholeMultiplier) {
		console.log("Multiplier increased:", currentWholeMultiplier); // Debug log 
		LK.getSound('multiplier').play();
		var randomVoice = 'voice' + (Math.floor(Math.random() * 5) + 1);
		LK.getSound(randomVoice).play();
		var popupText = new Text2(currentWholeMultiplier + "X MULTIPLIER!", {
			size: 120,
			fill: 0xFFFFFF,
			align: 'center',
			weight: 800
		});
		popupText.anchor.set(0.5, 0.5);
		LK.gui.center.addChild(popupText);
		popupText.scale.set(0.1);
		// Animate in
		tween(popupText.scale, {
			x: 1.2,
			y: 1.2
		}, {
			duration: 400,
			easing: tween.elasticOut,
			onFinish: function onFinish() {
				// Animate out
				tween(popupText, {
					alpha: 0,
					y: popupText.y - 100
				}, {
					duration: 800,
					delay: 600,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						LK.gui.center.removeChild(popupText);
						popupText.destroy();
					}
				});
			}
		});
		lastWholeMultiplier = currentWholeMultiplier;
	}
}; ===================================================================
--- original.js
+++ change.js
@@ -367,8 +367,9 @@
 	// Physics variables
 	var velocityY = 0;
 	var lastWaveY = 2732 * 0.85;
 	var initialized = false;
+	var activePopups = [];
 	// Setup surfer graphics
 	var surferGraphics = self.attachAsset('surfer', {
 		anchorX: 0.5,
 		anchorY: 0.8
@@ -823,14 +824,9 @@
 	}
 	self.update = function () {
 		// Always calculate wave points first, regardless of calibration state
 		var targetPitch = 0;
-		// Reset everything if pitch is null/undefined (face lost)
-		if (facekit.pitch === null || facekit.pitch === undefined) {
-			targetPitch = 0;
-			lastPitch = 0;
-			smoothedHeight = 0;
-		} else if (facekit.volume > 0.5) {
+		if (facekit.volume > 0.5) {
 			var normalizedPitch = (facekit.pitch - MIN_PITCH) / (MAX_PITCH - MIN_PITCH);
 			normalizedPitch = Math.max(0, Math.min(1, normalizedPitch));
 			targetPitch = normalizedPitch * 0.6 + lastPitch * 0.4;
 		}
:quality(85)/https://cdn.frvr.ai/67a93eb368c182ca2db2af7e.png%3F3) 
 A surfer standing and riding on a surfboard. Side profile. Cartoon. Full body. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67aa1245badf5001415a636c.png%3F3) 
 A peaked blue rock. Cartoon style.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67aa1bb8badf5001415a63b2.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/67aa2e23badf5001415a645e.png%3F3) 
 Poseidon’s face. Cartoon style.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67aa3a5b89fd120dcff03110.png%3F3) 
 An opened pair of lips as if singing . Light Skin color. Cell shading vector art style. Facing forward. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67aa765f89fd120dcff031bb.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/67aaacc72308eb0585f20705.png%3F3) 
 A tropical fish. Cartoon.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67ae55fa8a1a41a014d09fa5.png%3F3)