User prompt
can you add a button somewhere to disable the camera ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
make it so! ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/facekit.v1
User prompt
Please fix the bug: 'LK.Shape is not a constructor' in or related to this line: 'var micBar = new LK.Shape({' Line Number: 361
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: facekit.init is not a function' in or related to this line: 'facekit.init({' Line Number: 643
User prompt
Please fix the bug: 'Uncaught TypeError: facekit.init is not a function' in or related to this line: 'facekit.init({' Line Number: 643 ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
make it so! ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
is it possible to create unlockable ships for the player? for then the player completes a round win or lose I would like for them to be able to unlock 1 of 5 locked ships each time and each of these ships for the player that they unlock is randomly generated and will get 1 more life added. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
I love these ideas! please make it so !
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: LK.musicTime is not a function' in or related to this line: 'musicStartTime = LK.musicTime(); // Track when music started using music time' Line Number: 465
User prompt
Update the block-catching sound timing in "Sound Surfer" so that the sounds played when the player catches a block are better synchronized with the beat of the currently playing music track. Specifically: 1. Use `LK.musicTime()` instead of `Date.now()` to calculate the time since the current track started. This will give more accurate sync with the actual audio. 2. Calculate the current beat position based on a beat duration that dynamically adjusts with game speed. For example: ```javascript var baseBPM = 120; var currentBPM = baseBPM * gameSpeed; var beatLength = 60000 / currentBPM; // in ms
User prompt
make it so! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
yup that sounds perfect! make it so!
User prompt
for when the player catches a normal block can you make sure that the sound matches a note/beat from the current track playing? or make it so that it stays in tune and in rhythm of the current track playing ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: Cannot use 'in' operator to search for 'scaleX' in undefined' in or related to this line: 'tween(lifeDisplays[lifeIdx], {' Line Number: 497 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
next can we add another block thats a bomb that will take 2 lives from the player if the player touches it. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
oh yes this would be amazing! make it so !
User prompt
could you also add another mechanic where after the first song ends move onto another and then eventually go through all the available tracks. Once the player goes through all the tracks available without repeating any of the tracks the player will then get the You win menu and with their player stats like their score and highest combo ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ok can we add another mechanic for the player? I would like to add a player life system. the player starts with 3 lives that are somewhere easily visablee on the screen that fits the neon retrowave theme for the game. For every missed block the player will lose 1 life. if the player loses all their lives then the player will get a game over menu with an option to try again! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Instead of player HP based on a percentage could we just instead change the value to a total of 3? They have 3 lives and lose the game if all 3 are lost. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
I cant see the HP bar at all
User prompt
Ok can we add another mechanic for the player? I would like to add a HP Bar at the very bottom below the players ship. noticeable bright green bar that will flash red during a missed block. centered but also doesnt get in the way of other objects. This HP Bar will start at 100% and every missed block decreases the value of the HP Bar anywhere from 5% to 10%. When the HP reaches 0 or below the player loses and gets a giant flashy neon glow and bright game over menu with the option to try again! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
can we add 2 more tracks for music for classic mode? 1 track lofi and the other a retrowave track with a good steady beat.
User prompt
could we take some of the sounds from the music generated and turn them into sound effects for the player when they collect a block ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ var BackgroundGrid = Container.expand(function () { var self = Container.call(this); // Create horizontal grid lines self.horizontalLines = []; for (var i = 0; i < 15; i++) { var line = self.attachAsset('gridLine', { anchorX: 0, anchorY: 0.5, alpha: 0.3 }); line.y = i * 200 - 400; self.horizontalLines.push(line); } // Create vertical grid lines self.verticalLines = []; for (var j = 0; j < 8; j++) { var vLine = self.attachAsset('gridLineVertical', { anchorX: 0.5, anchorY: 0, alpha: 0.2 }); vLine.x = j * 300; self.verticalLines.push(vLine); } self.update = function () { // Move horizontal lines down for (var i = 0; i < self.horizontalLines.length; i++) { var line = self.horizontalLines[i]; line.y += 2; // Reset line position when it goes off screen if (line.y > 2800) { line.y = -100; } // Fade effect based on distance from center var distanceFromCenter = Math.abs(line.y - 1366); var maxDistance = 1366; line.alpha = 0.3 * (1 - distanceFromCenter / maxDistance); } }; return self; }); var Block = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('block', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); self.speed = 8; self.lane = 0; self.caught = false; // Random neon colors var colors = [0xff00ff, 0x00ffff, 0xffff00, 0xff0066, 0x66ff00]; blockGraphics.tint = colors[Math.floor(Math.random() * colors.length)]; self.update = function () { self.y += self.speed; }; return self; }); var BoosterBlock = Container.expand(function () { var self = Container.call(this); var boosterGraphics = self.attachAsset('booster', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); self.speed = 8; self.lane = 0; self.caught = false; // Distinctive golden/yellow color for booster boosterGraphics.tint = 0xFFD700; // Add pulsing animation to make it stand out tween(boosterGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(boosterGraphics, { scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { // Restart the pulsing animation if (!self.caught) { tween(boosterGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, easing: tween.easeInOut }); } } }); } }); self.update = function () { self.y += self.speed; }; return self; }); var Ship = Container.expand(function (shipType) { var self = Container.call(this); // Use the provided shipType or default to classicShip var assetType = shipType || 'classicShip'; var shipGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5, scaleX: 3.0, scaleY: 3.0 }); // Add glow effect shipGraphics.filters = []; self.currentLane = 1; // 0 = left, 1 = center, 2 = right self.targetX = 1024; // center position self.update = function () { // Smooth movement to target lane var diff = self.targetX - self.x; if (Math.abs(diff) > 2) { self.x += diff * 0.15; } else { self.x = self.targetX; } }; self.moveToLane = function (lane) { self.currentLane = lane; if (lane === 0) { self.targetX = 341; // left lane } else if (lane === 1) { self.targetX = 1024; // center lane } else if (lane === 2) { self.targetX = 1707; // right lane } // Add movement animation tween(shipGraphics, { scaleX: 3.6, scaleY: 2.4 }, { duration: 100, onFinish: function onFinish() { tween(shipGraphics, { scaleX: 3.0, scaleY: 3.0 }, { duration: 100 }); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0a0a0a }); /**** * Game Code ****/ // Create synthwave background with gradient effect game.setBackgroundColor(0x270050); // Create moving background grid var backgroundGrid = game.addChild(new BackgroundGrid()); // Array of synthwave tracks for classic mode var synthwaveTracks = ['synthwave1', 'synthwave2', 'synthwave3']; // Game state var gameMode = 'menu'; // 'menu', 'classic', 'microphone' var ship; var blocks = []; var score = 0; var combo = 0; var bestCombo = 0; var lastSpawnTime = 0; var spawnInterval = 1000; // 1 second var gameSpeed = 1.0; // Speed multiplier for the game var baseBlockSpeed = 8; // Base speed for blocks var currentMusicTrack = null; // Track current playing music // Beat detection variables var audioBuffer = []; var beatThreshold = 0.4; var lastBeatTime = 0; var minBeatInterval = 200; // Minimum ms between beats var volumeHistory = []; var bufferSize = 10; var beatSensitivity = 1.5; // Lane positions - equal width lanes var lanePositions = [341, 1024, 1707]; // UI Elements var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0x00FFFF }); scoreTxt.anchor.set(0, 0); scoreTxt.x = 50; scoreTxt.y = 50; LK.gui.topLeft.addChild(scoreTxt); var comboTxt = new Text2('Combo: 0', { size: 50, fill: 0xFF00FF }); comboTxt.anchor.set(0, 0); comboTxt.x = 50; comboTxt.y = 120; LK.gui.topLeft.addChild(comboTxt); // Create mode selection buttons with neon glow outline var classicButton = new Text2('1. CLASSIC MODE\nBuilt-in synthwave music', { size: 60, fill: 0x00FFFF, stroke: 0x00FFFF, strokeThickness: 3 }); classicButton.anchor.set(0.5, 0.5); classicButton.x = 0; classicButton.y = -300; LK.gui.center.addChild(classicButton); var micButton = new Text2('2. MICROPHONE MODE\nSync with your music', { size: 60, fill: 0xFF00FF, stroke: 0xFF00FF, strokeThickness: 3 }); micButton.anchor.set(0.5, 0.5); micButton.x = 0; micButton.y = -100; LK.gui.center.addChild(micButton); var instructionTxt = new Text2('TAP A BUTTON TO SELECT MODE', { size: 50, fill: 0xFFFFFF }); instructionTxt.anchor.set(0.5, 0.5); instructionTxt.y = 100; LK.gui.center.addChild(instructionTxt); // Create lane dividers var lane1 = game.addChild(LK.getAsset('lane1', { x: 682, y: 0 })); var lane2 = game.addChild(LK.getAsset('lane2', { x: 1366, y: 0 })); // Create ship ship = game.addChild(new Ship()); ship.x = 1024; ship.y = 2400; function startGame(mode) { gameMode = mode; score = 0; combo = 0; bestCombo = 0; blocks = []; lastSpawnTime = 0; gameSpeed = 1.0; // Reset game speed // Reset beat detection variables audioBuffer = []; volumeHistory = []; lastBeatTime = 0; // Hide menu elements classicButton.visible = false; micButton.visible = false; instructionTxt.visible = false; // Destroy existing ship and create new one with appropriate asset if (ship) { ship.destroy(); } // Create ship with mode-specific asset if (mode === 'classic') { ship = game.addChild(new Ship('classicShip')); } else { ship = game.addChild(new Ship('microphoneShip')); } ship.x = 1024; ship.y = 2400; // Start background music only in classic mode if (mode === 'classic') { // Randomly select one of the three synthwave tracks var randomTrack = synthwaveTracks[Math.floor(Math.random() * synthwaveTracks.length)]; currentMusicTrack = randomTrack; LK.playMusic(randomTrack); } else { // Stop background music in microphone mode to focus on external audio currentMusicTrack = null; LK.stopMusic(); } updateUI(); } function spawnBlock() { var block; // 15% chance to spawn a booster block if (Math.random() < 0.15) { block = new BoosterBlock(); } else { block = new Block(); } var lane; if (gameMode === 'microphone') { // Create more musical patterns based on audio intensity var intensity = facekit.volume; if (intensity > 0.8) { // High intensity - spawn in multiple lanes or center lane = Math.random() > 0.5 ? 1 : Math.floor(Math.random() * 3); } else if (intensity > 0.5) { // Medium intensity - prefer outer lanes lane = Math.random() > 0.5 ? 0 : 2; } else { // Low intensity - single random lane lane = Math.floor(Math.random() * 3); } } else { // Classic mode - random lane lane = Math.floor(Math.random() * 3); } block.lane = lane; block.x = lanePositions[lane]; block.y = -50; block.speed = baseBlockSpeed * gameSpeed; // Apply game speed multiplier blocks.push(block); game.addChild(block); } function updateUI() { scoreTxt.setText('Score: ' + score); comboTxt.setText('Combo: ' + combo + ' (Best: ' + bestCombo + ')'); } function checkCollisions() { for (var i = blocks.length - 1; i >= 0; i--) { var block = blocks[i]; // Check if block is in ship's catch zone if (!block.caught && block.y >= ship.y - 100 && block.y <= ship.y + 100) { if (block.lane === ship.currentLane) { // Block caught! block.caught = true; // Check if it's a booster block if (block instanceof BoosterBlock) { // Booster effects score += 25 + combo * 3; // More points for booster combo += 2; // Extra combo bonus // Increase game speed (cap at 2.5x) gameSpeed = Math.min(gameSpeed + 0.2, 2.5); // Apply speed to all existing blocks for (var j = 0; j < blocks.length; j++) { blocks[j].speed = baseBlockSpeed * gameSpeed; } // Restart music with faster tempo (only in classic mode) if (gameMode === 'classic' && currentMusicTrack) { LK.stopMusic(); // Small delay before restarting music to avoid audio glitches LK.setTimeout(function () { LK.playMusic(currentMusicTrack); }, 50); } // Special visual feedback for booster LK.effects.flashScreen(0xFFD700, 300); LK.effects.flashObject(ship, 0xFFD700, 500); // Play layered synthwave sounds for booster LK.getSound('synthBass').play(); LK.setTimeout(function () { LK.getSound('synthLead').play(); }, 100); } else { // Regular block score += 10 + combo * 2; combo++; } if (combo > bestCombo) { bestCombo = combo; } // Visual feedback LK.effects.flashObject(block, 0xffffff, 200); tween(block, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200 }); // Play random synthwave sound effect var synthSounds = ['synthBass', 'synthLead', 'synthDrum', 'synthChord']; var randomSound = synthSounds[Math.floor(Math.random() * synthSounds.length)]; LK.getSound(randomSound).play(); updateUI(); // Remove block block.destroy(); blocks.splice(i, 1); continue; } } // Check if block missed (passed ship) if (!block.caught && block.y > ship.y + 150) { if (block.lane === ship.currentLane) { // Block missed - reset combo combo = 0; LK.effects.flashScreen(0xff0000, 300); LK.getSound('miss').play(); updateUI(); } block.caught = true; // Mark as processed } // Remove blocks that are off screen if (block.y > 2800) { block.destroy(); blocks.splice(i, 1); } } } function detectBeat() { var currentVolume = facekit.volume; var currentTime = Date.now(); // Add current volume to history buffer volumeHistory.push(currentVolume); if (volumeHistory.length > bufferSize) { volumeHistory.shift(); } // Calculate average volume from buffer var avgVolume = 0; for (var i = 0; i < volumeHistory.length; i++) { avgVolume += volumeHistory[i]; } avgVolume = avgVolume / volumeHistory.length; // Detect beat: current volume significantly higher than average var volumeSpike = currentVolume > avgVolume * beatSensitivity; var timeSinceLastBeat = currentTime - lastBeatTime; var beatDetected = volumeSpike && currentVolume > beatThreshold && timeSinceLastBeat > minBeatInterval; if (beatDetected) { lastBeatTime = currentTime; // Add visual feedback for beat detection LK.effects.flashScreen(0x440088, 100); return true; } return false; } function shouldSpawnBlock() { if (gameMode === 'microphone') { // Spawn based on beat detection from microphone input return detectBeat(); } else { // Classic mode - spawn every second return LK.ticks - lastSpawnTime >= spawnInterval / (1000 / 60); } } // Button event handlers classicButton.down = function (x, y, obj) { if (gameMode === 'menu') { // Add button press animation tween(classicButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 100, onFinish: function onFinish() { tween(classicButton, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); startGame('classic'); } }; micButton.down = function (x, y, obj) { if (gameMode === 'menu') { // Add button press animation tween(micButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 100, onFinish: function onFinish() { tween(micButton, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); startGame('microphone'); } }; // Touch controls for lane switching during gameplay game.down = function (x, y, obj) { if (gameMode === 'menu') { return; } // Lane switching if (x < 1024) { // Left side tapped - move left if (ship.currentLane > 0) { ship.moveToLane(ship.currentLane - 1); } } else { // Right side tapped - move right if (ship.currentLane < 2) { ship.moveToLane(ship.currentLane + 1); } } }; // Main game update game.update = function () { if (gameMode === 'menu') { return; } // Spawn blocks if (shouldSpawnBlock()) { spawnBlock(); lastSpawnTime = LK.ticks; } // Check collisions checkCollisions(); // Game over condition (optional - can be removed for endless play) if (score >= 500) { LK.showYouWin(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
var BackgroundGrid = Container.expand(function () {
var self = Container.call(this);
// Create horizontal grid lines
self.horizontalLines = [];
for (var i = 0; i < 15; i++) {
var line = self.attachAsset('gridLine', {
anchorX: 0,
anchorY: 0.5,
alpha: 0.3
});
line.y = i * 200 - 400;
self.horizontalLines.push(line);
}
// Create vertical grid lines
self.verticalLines = [];
for (var j = 0; j < 8; j++) {
var vLine = self.attachAsset('gridLineVertical', {
anchorX: 0.5,
anchorY: 0,
alpha: 0.2
});
vLine.x = j * 300;
self.verticalLines.push(vLine);
}
self.update = function () {
// Move horizontal lines down
for (var i = 0; i < self.horizontalLines.length; i++) {
var line = self.horizontalLines[i];
line.y += 2;
// Reset line position when it goes off screen
if (line.y > 2800) {
line.y = -100;
}
// Fade effect based on distance from center
var distanceFromCenter = Math.abs(line.y - 1366);
var maxDistance = 1366;
line.alpha = 0.3 * (1 - distanceFromCenter / maxDistance);
}
};
return self;
});
var Block = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
self.speed = 8;
self.lane = 0;
self.caught = false;
// Random neon colors
var colors = [0xff00ff, 0x00ffff, 0xffff00, 0xff0066, 0x66ff00];
blockGraphics.tint = colors[Math.floor(Math.random() * colors.length)];
self.update = function () {
self.y += self.speed;
};
return self;
});
var BoosterBlock = Container.expand(function () {
var self = Container.call(this);
var boosterGraphics = self.attachAsset('booster', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
self.speed = 8;
self.lane = 0;
self.caught = false;
// Distinctive golden/yellow color for booster
boosterGraphics.tint = 0xFFD700;
// Add pulsing animation to make it stand out
tween(boosterGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(boosterGraphics, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart the pulsing animation
if (!self.caught) {
tween(boosterGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.easeInOut
});
}
}
});
}
});
self.update = function () {
self.y += self.speed;
};
return self;
});
var Ship = Container.expand(function (shipType) {
var self = Container.call(this);
// Use the provided shipType or default to classicShip
var assetType = shipType || 'classicShip';
var shipGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
scaleY: 3.0
});
// Add glow effect
shipGraphics.filters = [];
self.currentLane = 1; // 0 = left, 1 = center, 2 = right
self.targetX = 1024; // center position
self.update = function () {
// Smooth movement to target lane
var diff = self.targetX - self.x;
if (Math.abs(diff) > 2) {
self.x += diff * 0.15;
} else {
self.x = self.targetX;
}
};
self.moveToLane = function (lane) {
self.currentLane = lane;
if (lane === 0) {
self.targetX = 341; // left lane
} else if (lane === 1) {
self.targetX = 1024; // center lane
} else if (lane === 2) {
self.targetX = 1707; // right lane
}
// Add movement animation
tween(shipGraphics, {
scaleX: 3.6,
scaleY: 2.4
}, {
duration: 100,
onFinish: function onFinish() {
tween(shipGraphics, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 100
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a0a
});
/****
* Game Code
****/
// Create synthwave background with gradient effect
game.setBackgroundColor(0x270050);
// Create moving background grid
var backgroundGrid = game.addChild(new BackgroundGrid());
// Array of synthwave tracks for classic mode
var synthwaveTracks = ['synthwave1', 'synthwave2', 'synthwave3'];
// Game state
var gameMode = 'menu'; // 'menu', 'classic', 'microphone'
var ship;
var blocks = [];
var score = 0;
var combo = 0;
var bestCombo = 0;
var lastSpawnTime = 0;
var spawnInterval = 1000; // 1 second
var gameSpeed = 1.0; // Speed multiplier for the game
var baseBlockSpeed = 8; // Base speed for blocks
var currentMusicTrack = null; // Track current playing music
// Beat detection variables
var audioBuffer = [];
var beatThreshold = 0.4;
var lastBeatTime = 0;
var minBeatInterval = 200; // Minimum ms between beats
var volumeHistory = [];
var bufferSize = 10;
var beatSensitivity = 1.5;
// Lane positions - equal width lanes
var lanePositions = [341, 1024, 1707];
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0x00FFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 50;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var comboTxt = new Text2('Combo: 0', {
size: 50,
fill: 0xFF00FF
});
comboTxt.anchor.set(0, 0);
comboTxt.x = 50;
comboTxt.y = 120;
LK.gui.topLeft.addChild(comboTxt);
// Create mode selection buttons with neon glow outline
var classicButton = new Text2('1. CLASSIC MODE\nBuilt-in synthwave music', {
size: 60,
fill: 0x00FFFF,
stroke: 0x00FFFF,
strokeThickness: 3
});
classicButton.anchor.set(0.5, 0.5);
classicButton.x = 0;
classicButton.y = -300;
LK.gui.center.addChild(classicButton);
var micButton = new Text2('2. MICROPHONE MODE\nSync with your music', {
size: 60,
fill: 0xFF00FF,
stroke: 0xFF00FF,
strokeThickness: 3
});
micButton.anchor.set(0.5, 0.5);
micButton.x = 0;
micButton.y = -100;
LK.gui.center.addChild(micButton);
var instructionTxt = new Text2('TAP A BUTTON TO SELECT MODE', {
size: 50,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.y = 100;
LK.gui.center.addChild(instructionTxt);
// Create lane dividers
var lane1 = game.addChild(LK.getAsset('lane1', {
x: 682,
y: 0
}));
var lane2 = game.addChild(LK.getAsset('lane2', {
x: 1366,
y: 0
}));
// Create ship
ship = game.addChild(new Ship());
ship.x = 1024;
ship.y = 2400;
function startGame(mode) {
gameMode = mode;
score = 0;
combo = 0;
bestCombo = 0;
blocks = [];
lastSpawnTime = 0;
gameSpeed = 1.0; // Reset game speed
// Reset beat detection variables
audioBuffer = [];
volumeHistory = [];
lastBeatTime = 0;
// Hide menu elements
classicButton.visible = false;
micButton.visible = false;
instructionTxt.visible = false;
// Destroy existing ship and create new one with appropriate asset
if (ship) {
ship.destroy();
}
// Create ship with mode-specific asset
if (mode === 'classic') {
ship = game.addChild(new Ship('classicShip'));
} else {
ship = game.addChild(new Ship('microphoneShip'));
}
ship.x = 1024;
ship.y = 2400;
// Start background music only in classic mode
if (mode === 'classic') {
// Randomly select one of the three synthwave tracks
var randomTrack = synthwaveTracks[Math.floor(Math.random() * synthwaveTracks.length)];
currentMusicTrack = randomTrack;
LK.playMusic(randomTrack);
} else {
// Stop background music in microphone mode to focus on external audio
currentMusicTrack = null;
LK.stopMusic();
}
updateUI();
}
function spawnBlock() {
var block;
// 15% chance to spawn a booster block
if (Math.random() < 0.15) {
block = new BoosterBlock();
} else {
block = new Block();
}
var lane;
if (gameMode === 'microphone') {
// Create more musical patterns based on audio intensity
var intensity = facekit.volume;
if (intensity > 0.8) {
// High intensity - spawn in multiple lanes or center
lane = Math.random() > 0.5 ? 1 : Math.floor(Math.random() * 3);
} else if (intensity > 0.5) {
// Medium intensity - prefer outer lanes
lane = Math.random() > 0.5 ? 0 : 2;
} else {
// Low intensity - single random lane
lane = Math.floor(Math.random() * 3);
}
} else {
// Classic mode - random lane
lane = Math.floor(Math.random() * 3);
}
block.lane = lane;
block.x = lanePositions[lane];
block.y = -50;
block.speed = baseBlockSpeed * gameSpeed; // Apply game speed multiplier
blocks.push(block);
game.addChild(block);
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
comboTxt.setText('Combo: ' + combo + ' (Best: ' + bestCombo + ')');
}
function checkCollisions() {
for (var i = blocks.length - 1; i >= 0; i--) {
var block = blocks[i];
// Check if block is in ship's catch zone
if (!block.caught && block.y >= ship.y - 100 && block.y <= ship.y + 100) {
if (block.lane === ship.currentLane) {
// Block caught!
block.caught = true;
// Check if it's a booster block
if (block instanceof BoosterBlock) {
// Booster effects
score += 25 + combo * 3; // More points for booster
combo += 2; // Extra combo bonus
// Increase game speed (cap at 2.5x)
gameSpeed = Math.min(gameSpeed + 0.2, 2.5);
// Apply speed to all existing blocks
for (var j = 0; j < blocks.length; j++) {
blocks[j].speed = baseBlockSpeed * gameSpeed;
}
// Restart music with faster tempo (only in classic mode)
if (gameMode === 'classic' && currentMusicTrack) {
LK.stopMusic();
// Small delay before restarting music to avoid audio glitches
LK.setTimeout(function () {
LK.playMusic(currentMusicTrack);
}, 50);
}
// Special visual feedback for booster
LK.effects.flashScreen(0xFFD700, 300);
LK.effects.flashObject(ship, 0xFFD700, 500);
// Play layered synthwave sounds for booster
LK.getSound('synthBass').play();
LK.setTimeout(function () {
LK.getSound('synthLead').play();
}, 100);
} else {
// Regular block
score += 10 + combo * 2;
combo++;
}
if (combo > bestCombo) {
bestCombo = combo;
}
// Visual feedback
LK.effects.flashObject(block, 0xffffff, 200);
tween(block, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200
});
// Play random synthwave sound effect
var synthSounds = ['synthBass', 'synthLead', 'synthDrum', 'synthChord'];
var randomSound = synthSounds[Math.floor(Math.random() * synthSounds.length)];
LK.getSound(randomSound).play();
updateUI();
// Remove block
block.destroy();
blocks.splice(i, 1);
continue;
}
}
// Check if block missed (passed ship)
if (!block.caught && block.y > ship.y + 150) {
if (block.lane === ship.currentLane) {
// Block missed - reset combo
combo = 0;
LK.effects.flashScreen(0xff0000, 300);
LK.getSound('miss').play();
updateUI();
}
block.caught = true; // Mark as processed
}
// Remove blocks that are off screen
if (block.y > 2800) {
block.destroy();
blocks.splice(i, 1);
}
}
}
function detectBeat() {
var currentVolume = facekit.volume;
var currentTime = Date.now();
// Add current volume to history buffer
volumeHistory.push(currentVolume);
if (volumeHistory.length > bufferSize) {
volumeHistory.shift();
}
// Calculate average volume from buffer
var avgVolume = 0;
for (var i = 0; i < volumeHistory.length; i++) {
avgVolume += volumeHistory[i];
}
avgVolume = avgVolume / volumeHistory.length;
// Detect beat: current volume significantly higher than average
var volumeSpike = currentVolume > avgVolume * beatSensitivity;
var timeSinceLastBeat = currentTime - lastBeatTime;
var beatDetected = volumeSpike && currentVolume > beatThreshold && timeSinceLastBeat > minBeatInterval;
if (beatDetected) {
lastBeatTime = currentTime;
// Add visual feedback for beat detection
LK.effects.flashScreen(0x440088, 100);
return true;
}
return false;
}
function shouldSpawnBlock() {
if (gameMode === 'microphone') {
// Spawn based on beat detection from microphone input
return detectBeat();
} else {
// Classic mode - spawn every second
return LK.ticks - lastSpawnTime >= spawnInterval / (1000 / 60);
}
}
// Button event handlers
classicButton.down = function (x, y, obj) {
if (gameMode === 'menu') {
// Add button press animation
tween(classicButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(classicButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
startGame('classic');
}
};
micButton.down = function (x, y, obj) {
if (gameMode === 'menu') {
// Add button press animation
tween(micButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(micButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
startGame('microphone');
}
};
// Touch controls for lane switching during gameplay
game.down = function (x, y, obj) {
if (gameMode === 'menu') {
return;
}
// Lane switching
if (x < 1024) {
// Left side tapped - move left
if (ship.currentLane > 0) {
ship.moveToLane(ship.currentLane - 1);
}
} else {
// Right side tapped - move right
if (ship.currentLane < 2) {
ship.moveToLane(ship.currentLane + 1);
}
}
};
// Main game update
game.update = function () {
if (gameMode === 'menu') {
return;
}
// Spawn blocks
if (shouldSpawnBlock()) {
spawnBlock();
lastSpawnTime = LK.ticks;
}
// Check collisions
checkCollisions();
// Game over condition (optional - can be removed for endless play)
if (score >= 500) {
LK.showYouWin();
}
};
synthwave neon glow audiosurf or f-zero like ship. In-Game asset. 2d. High contrast. No shadows
faint glowing outlines with a shimmer effect retro synthwave style. In-Game asset. 2d. High contrast. No shadows
a musical note thats bright and neon thats also really cool looking. In-Game asset. 2d. High contrast. No shadows
synthwave bright neon glow audiosurf or f-zero like ship In-Game asset. 2d. High contrast. No shadows
synthwave bright neon glow audiosurf or f-zero like ship In-Game asset. 2d. High contrast. No shadows. facing upright vertical
a musical note thats bright and neon thats also really cool looking. In-Game asset. 2d. High contrast. No shadows
- Shape: a glowing neon **circle or hexagon** - Color: bright **red or magenta** - Inner symbol: a small white or yellow **skull**, **explosion**, or **⚠️ warning icon** in the center - Glow: apply a soft outer glow that pulses slightly - Visual style: match the **synthwave aesthetic** (think neon, arcade, retro-futuristic) - Size: same as the existing note blocks - Animation: gently pulsate or shimmer while falling. In-Game asset. 2d. High contrast. No shadows
a bright laser vertical line retro style. In-Game asset. 2d. High contrast. No shadows. In-Game asset. 2d. High contrast. No shadows
a line that is set to the theme of this game that looks like lightsabre. In-Game asset. 2d. High contrast. No shadows
synthwave bright neon glow audiosurf or f-zero like ship In-Game asset. 2d. High contrast. No shadows. facing upright vertical 3d like