User prompt
Update as needed with: // When creating the core in createUI, store the reference: var vibeCore = LK.getAsset('vibecore', { anchorX: 0.5, anchorY: 0.5, x: 2048/2, y: 2732/2 - 200 }); gameState.vibeCore = vibeCore; // Store reference vibeContainer.addChild(vibeCore);
User prompt
Update as needed with: function playCard(card) { // Early returns stay the same if (currentHand.indexOf(card) === -1) { return; } if (gameState.cardsPlayed >= gameState.maxCardsPerDay) { card.targetX = card.originalX; card.targetY = card.originalY; return; } // All the game state changes stay the same // [existing code for points, lines, etc.] // Find the vibecore var vibeCore = gameState.vibeContainer.children.find(child => child.assetId === 'vibecore'); // Animate card "sinking" into core and core pulsing tween(card, { x: gameState.stackArea.x, y: gameState.stackArea.y, scaleX: 0.2, scaleY: 0.2, alpha: 0 }, { duration: 300, onFinish: function() { if (vibeCore) { tween(vibeCore.scale, { x: 1.2, y: 1.2 }, { duration: 150, onFinish: function() { tween(vibeCore.scale, { x: 1, y: 1 }, { duration: 150 }); } }); } // Rest of the finish handler stays the same gameState.cardStack.push(card); checkForBugs(card.bugChance); updateStatsDisplay(); positionCardsInHand(); if (currentHand.length < HAND_SIZE) { drawHand(); } checkGameState(); } }); } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Change card text to white.
User prompt
Update as needed with: // In the Card class, modify the card background creation: var Card = Container.expand(function(type, promptText, codeLines, vibePoints, contextImpact, bugChance) { var self = Container.call(this); // ... existing properties ... // Replace the card background creation with: var cardAsset; switch(type.toLowerCase()) { case 'ui': cardAsset = 'uicard'; break; case 'database': cardAsset = 'databasecard'; break; case 'api': cardAsset = 'apicard'; break; case 'security': cardAsset = 'securitycard'; break; case 'refactor': case 'coffee': case 'debug': cardAsset = 'specialcard'; break; default: cardAsset = 'basiccard'; } var cardBg = self.attachAsset(cardAsset, { anchorX: 0.5, anchorY: 0.5 }); // ... rest of Card class code ... });
User prompt
Update as needed with: function createStackArea() { // Modify these parts: // When creating console window var codeConsole = new Container(); codeConsole.alpha = 0; // Set to 0 to hide it // When creating stack background var stackBg = LK.getAsset('card', { anchorX: 0.5, anchorY: 0.5, width: 450, height: 550, color: 0x1a1f26, alpha: 0 // Set to 0 to hide it }); // When creating stack label and borders stackLabel.alpha = 0; topBorder.alpha = 0; bottomBorder.alpha = 0; // In the side borders loop: leftBorder.alpha = 0; rightBorder.alpha = 0; // When creating vibe display var vibeDisplay = new Container(); vibeDisplay.alpha = 0; // Set to 0 to hide it }
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'child.text.startsWith')' in or related to this line: 'return child instanceof Text2 && child.text.startsWith("DAY");' Line Number: 1528
User prompt
Update as needed with: function updateStatsDisplay() { // [Keep all existing update code] // Update vibe day indicator if it exists if (gameState.vibeContainer) { // Find the day indicator in the vibe container's children var vibeDayIndicator = gameState.vibeContainer.children.find(child => child instanceof Text2 && child.text.startsWith("DAY")); if (vibeDayIndicator) { vibeDayIndicator.setText("DAY " + gameState.day); } } }
User prompt
Update as needed with: function createUI() { // [Keep all existing UI creation code here unchanged] // Add vibe layer after all existing UI is created // Create a top-level vibe container that sits above everything else var vibeContainer = new Container(); game.addChild(vibeContainer); // This puts it on top of existing UI // Add vibe background var vibeBackground = LK.getAsset('vibebackground', { anchorX: 0.5, anchorY: 0.5, x: 2048/2, y: 2732/2 }); vibeContainer.addChild(vibeBackground); // Add vibe core in center var vibeCore = LK.getAsset('vibecore', { anchorX: 0.5, anchorY: 0.5, x: 2048/2, y: 2732/2 - 200 // Slightly above center }); vibeContainer.addChild(vibeCore); // Stylized day counter (we can make this more vibe-appropriate later) var vibeDayIndicator = new Text2("DAY " + gameState.day, { size: 75, fill: 0x00ffff // Cyan color for vibe aesthetic }); vibeDayIndicator.anchor.set(0.5, 0.5); vibeDayIndicator.x = 1848; vibeDayIndicator.y = 200; vibeContainer.addChild(vibeDayIndicator); // Stylized end day button var vibeEndDayButton = new MenuButton("END DAY", endDay); vibeEndDayButton.x = 1848; vibeEndDayButton.y = 400; vibeEndDayButton.scale.set(1.2); // Make it slightly larger vibeContainer.addChild(vibeEndDayButton); // Store the container reference in gameState gameState.vibeContainer = vibeContainer; }
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'var localX = obj.event.data.getLocalPosition(this).x; // Get x relative to hitArea's origin' Line Number: 1216
User prompt
Update as needed with: } else if (bug instanceof LogicBug) { // Logic bug mini-game var gridSize = 5; var grid = new Container(); var breakpointCount = 0; // Progress indicator var progress = new Text2("Breakpoints: 0/3", { size: 70, // Match syntax bug size fill: 0xFFFFFF }); progress.anchor.set(0.5, 0.5); progress.y = 300; // Match syntax bug position gameContainer.addChild(progress); for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { var cell = LK.getAsset('menuButton', { width: 120, // Doubled from 60 height: 120, // Doubled from 60 color: 0x666666, // Lighter gray for inactive cells anchorX: 0.5, anchorY: 0.5 }); cell.x = (i - gridSize/2) * 140; // Doubled spacing from 70 cell.y = (j - gridSize/2) * 140; // Doubled spacing from 70 cell.interactive = true; cell.isBreakpoint = false; cell.down = function() { if (!this.isBreakpoint) { this.color = 0xFF0000; // Changed to red for active breakpoints this.isBreakpoint = true; breakpointCount++; LK.getSound('cardPlace').play(); } else { this.color = 0x666666; // Back to gray when deactivated this.isBreakpoint = false; breakpointCount--; } progress.setText(`Breakpoints: ${breakpointCount}/3`); if (breakpointCount === 3) { bugFixSuccess(bug, gameContainer); } }; grid.addChild(cell); } } gameContainer.addChild(grid); }
User prompt
Update as needed with: if (bug instanceof SyntaxBug) { // Syntax bug mini-game with doubled sizes var codeLines = [ "function brokenCode() {", " reutrn 'Hello World'", // Typo " cosole.log('Done');", // Typo "}" ]; // Double the panel size panel.width = 1600; panel.height = 1200; var errorPositions = [[1, 2], [2, 2]]; // Position of errors in code var foundErrors = 0; // Progress indicator with larger font var progress = new Text2("Errors found: 0/2", { size: 70, // Doubled from 35 fill: 0xFFFFFF }); progress.anchor.set(0.5, 0.5); progress.y = 300; // Doubled from 150 gameContainer.addChild(progress); // Display code with larger font and spacing codeLines.forEach((line, index) => { var codeLine = new Text2(line, { size: 90, // Doubled from 45 fill: 0xFFFFFF }); codeLine.anchor.set(0, 0); codeLine.x = -600; // Doubled from -300 codeLine.y = index * 100 - 200; // Doubled spacing and offset // Make the hit area for the whole line var hitArea = new Container(); var hitBox = LK.getAsset('menuButton', { width: 1200, // Wide enough for the full line height: 90, // Match text height color: 0x000000, alpha: 0.01 // Nearly invisible }); hitArea.addChild(hitBox); hitArea.x = codeLine.x; hitArea.y = codeLine.y; hitArea.interactive = true; hitArea.down = function(x, y) { var charPos = Math.floor((x + 600) / 40); // Adjusted for larger font if (errorPositions.some(pos => pos[0] === index && Math.abs(pos[1] - charPos) < 2)) { foundErrors++; progress.setText(`Errors found: ${foundErrors}/2`); codeLine.fill = 0x00FF00; LK.getSound('cardPlace').play(); // Feedback sound if (foundErrors >= errorPositions.length) { bugFixSuccess(bug, gameContainer); } } }; gameContainer.addChild(hitArea); gameContainer.addChild(codeLine); }); // Adjust title and instructions size title.size = 110; // Doubled from 55 title.y = -500; // Doubled from -250 instructions.size = 70; // Doubled from 35 instructions.y = -360; // Doubled from -180 // Adjust close button closeButton.scale.set(1.0); // Double from 0.5 closeButton.x = 600; // Doubled from 300 closeButton.y = -500; // Doubled from -250 }
User prompt
Update with: function startBugFix(bug) { var gameContainer = new Container(); gameContainer.x = 2048/2; gameContainer.y = 2732/2; game.addChild(gameContainer); // Add background panel var panel = LK.getAsset('menuButton', { width: 800, height: 600, color: 0x1a1f26, anchorX: 0.5, anchorY: 0.5 }); gameContainer.addChild(panel); // Add title var title = new Text2(bug instanceof SyntaxBug ? "Fix Syntax Errors!" : "Place Debug Breakpoints!", { size: 55, fill: 0xFFFFFF }); title.anchor.set(0.5, 0.5); title.y = -250; gameContainer.addChild(title); // Add instructions var instructions = new Text2(bug instanceof SyntaxBug ? "Click on the typos in the code to fix them" : "Place exactly 3 breakpoints to catch the bug", { size: 35, fill: 0xFFFFFF }); instructions.anchor.set(0.5, 0.5); instructions.y = -180; gameContainer.addChild(instructions); if (bug instanceof SyntaxBug) { // Syntax bug mini-game var codeLines = [ "function brokenCode() {", " reutrn 'Hello World'", // Typo " cosole.log('Done');", // Typo "}" ]; var errorPositions = [[1, 2], [2, 2]]; // Position of errors in code var foundErrors = 0; // Progress indicator var progress = new Text2("Errors found: 0/2", { size: 35, fill: 0xFFFFFF }); progress.anchor.set(0.5, 0.5); progress.y = 150; gameContainer.addChild(progress); // Display code codeLines.forEach((line, index) => { var codeLine = new Text2(line, { size: 45, fill: 0xFFFFFF }); codeLine.anchor.set(0, 0); codeLine.x = -300; codeLine.y = index * 50 - 100; codeLine.interactive = true; codeLine.down = function(x, y) { var charPos = Math.floor((x + 300) / 20); // Adjusted for centering if (errorPositions.some(pos => pos[0] === index && Math.abs(pos[1] - charPos) < 2)) { foundErrors++; progress.setText(`Errors found: ${foundErrors}/2`); codeLine.fill = 0x00FF00; LK.getSound('cardPlace').play(); // Feedback sound if (foundErrors >= errorPositions.length) { bugFixSuccess(bug, gameContainer); } } }; gameContainer.addChild(codeLine); }); } else if (bug instanceof LogicBug) { // Logic bug mini-game var gridSize = 5; var grid = new Container(); var breakpointCount = 0; // Progress indicator var progress = new Text2("Breakpoints: 0/3", { size: 35, fill: 0xFFFFFF }); progress.anchor.set(0.5, 0.5); progress.y = 150; gameContainer.addChild(progress); for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { var cell = LK.getAsset('menuButton', { width: 60, height: 60, color: 0x333333, anchorX: 0.5, anchorY: 0.5 }); cell.x = (i - gridSize/2) * 70; cell.y = (j - gridSize/2) * 70; cell.interactive = true; cell.isBreakpoint = false; cell.down = function() { if (!this.isBreakpoint) { this.color = 0x4A86E8; this.isBreakpoint = true; breakpointCount++; LK.getSound('cardPlace').play(); // Feedback sound } else { this.color = 0x333333; this.isBreakpoint = false; breakpointCount--; } progress.setText(`Breakpoints: ${breakpointCount}/3`); if (breakpointCount === 3) { bugFixSuccess(bug, gameContainer); } }; grid.addChild(cell); } } gameContainer.addChild(grid); } // Add close button var closeButton = new MenuButton("GIVE UP", function() { if (gameContainer && gameContainer.parent) { gameContainer.parent.removeChild(gameContainer); gameContainer.destroy(); } }); closeButton.scale.set(0.5); closeButton.x = 300; closeButton.y = -250; gameContainer.addChild(closeButton); }
User prompt
Update as needed with: function bugFixSuccess(bug, gameContainer) { // Remove vibe points cost gameState.vibePoints -= bug.vibePointsCost; // Remove code lines cost gameState.codeLines -= bug.codeLinesCost; // Decrement bug count gameState.bugs--; // Play success sound LK.getSound('bugFix').play(); // Remove bug with effect - check if bug still exists and has a parent if (bug && bug.parent) { tween(bug, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 300, onFinish: function() { if (bug && bug.parent) { bug.parent.removeChild(bug); bug.destroy(); } } }); } // Remove mini-game tween(gameContainer, { alpha: 0 }, { duration: 300, onFinish: function() { if (gameContainer && gameContainer.parent) { gameContainer.parent.removeChild(gameContainer); gameContainer.destroy(); } } }); // Update stats updateStatsDisplay(); } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Update with: } else if (bug instanceof LogicBug) { // Logic bug mini-game var gridSize = 5; var grid = new Container(); for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { var cell = LK.getAsset('menuButton', { width: 60, height: 60, color: 0x333333, anchorX: 0.5, anchorY: 0.5 }); cell.x = (i - gridSize/2) * 70; cell.y = (j - gridSize/2) * 70; cell.interactive = true; cell.down = function() { this.color = 0x4A86E8; checkLogicSolution(grid, bug, gameContainer); }; grid.addChild(cell); } } gameContainer.addChild(grid); }
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'var cell = new Sprite();' Line Number: 1188
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'bug.parent.removeChild')' in or related to this line: 'bug.parent.removeChild(bug);' Line Number: 1248
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'var cell = new Sprite();' Line Number: 1188
User prompt
Please fix the bug: 'TypeError: requestAnimationFrame is not a function. (In 'requestAnimationFrame(updateShake)', 'requestAnimationFrame' is undefined)' in or related to this line: 'requestAnimationFrame(updateShake);' Line Number: 616
Code edit (2 edits merged)
Please save this source code
User prompt
Replace self.down in the bug class with: self.down = function(x, y, obj) { if (gameState.vibePoints >= self.vibePointsCost) { startBugFix(this); } };
User prompt
Update with: function checkForBugs(bugChance) { // Adjust bug chance based on context collapse and threshold effect var adjustedBugChance = bugChance + (gameState.contextCollapse / MAX_CONTEXT_COLLAPSE * 0.3) + gameState.thresholdEffects.bugChanceModifier; // Special case for debug card if (bugChance < 0) { // Reduce bugs by a fixed amount var bugsToRemove = Math.min(gameState.bugs, Math.abs(Math.floor(bugChance * 10))); for (var i = 0; i < bugsToRemove; i++) { if (bugContainer.children.length > 0) { var bug = bugContainer.children[bugContainer.children.length - 1]; bugContainer.removeChild(bug); bug.destroy(); } } gameState.bugs -= bugsToRemove; return; } // Roll for bug if (Math.random() < adjustedBugChance && gameState.bugs < MAX_BUGS) { // Show detection sequence first showBugDetection(); // Create either a syntax or logic bug var bug = Math.random() < 0.5 ? new SyntaxBug() : new LogicBug(); // Position randomly in the project area bug.x = Math.random() * 1600 - 800; // -800 to 800 bug.y = Math.random() * 400 - 200; // -200 to 200 bugContainer.addChild(bug); gameState.bugs++; // Apply bug's effect immediately bug.effect(); // Animate bug appearance bug.scale.set(0); tween(bug, { scaleX: 1, scaleY: 1 }, { duration: 300 }); } } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Update as needed with: function playCard(card) { // [Previous code...] // Apply context impact with multiplier gameState.contextCollapse += card.contextImpact * gameState.thresholdEffects.contextMultiplier; gameState.contextCollapse = Math.max(0, Math.min(gameState.contextCollapse, MAX_CONTEXT_COLLAPSE)); // Immediately update effects after context change updateContextThresholdEffects(); // [Rest of the function...] } function endDay() { if (gameState.day >= MAX_DAYS) { evaluateProject(); } else { // [Previous day change code...] // Reduce context collapse and update effects gameState.contextCollapse = Math.max(0, gameState.contextCollapse - 10); updateContextThresholdEffects(); // [Rest of the function...] } } function initializeGame() { gameState = { // [Other initializations...] contextCollapse: 0, thresholdEffects: { bugChanceModifier: 0, maxCardsModifier: 0, contextMultiplier: 1, vibeCostModifier: 0 } }; // Make sure effects are initialized properly updateContextThresholdEffects(); // [Rest of the function...] }
User prompt
move the threshold effects text to centre on the x axis and move it up 7%
User prompt
update as needed with: // Modify updateStatsDisplay() function: function updateStatsDisplay() { // Create effects text let effectsText = ""; if (gameState.thresholdEffects.bugChanceModifier > 0) effectsText += "\nIncreased Bug Chance!"; if (gameState.thresholdEffects.maxCardsModifier < 0) effectsText += "\nReduced Cards Per Day!"; if (gameState.thresholdEffects.contextMultiplier > 1) effectsText += "\nDouble Context Impact!"; if (gameState.thresholdEffects.vibeCostModifier > 0) effectsText += "\nIncreased Vibe Costs!"; // Update stats text with effects statsText.setText( "Code Lines: " + gameState.codeLines + " / " + TARGET_CODE_LINES + "\nVibe Points: " + gameState.vibePoints + "\nBugs: " + gameState.bugs + "/" + MAX_BUGS + "\nCards: " + gameState.cardsPlayed + "/" + Math.max(1, gameState.maxCardsPerDay + gameState.thresholdEffects.maxCardsModifier) + (effectsText ? "\n" + effectsText : "") ); // Rest of function remains the same... }
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Bug = Container.expand(function () { var self = Container.call(this); var bugGraphic = self.attachAsset('bug', { anchorX: 0.5, anchorY: 0.5 }); self.codeLinesCost = Math.floor(Math.random() * 10) + 5; self.vibePointsCost = Math.floor(Math.random() * 3) + 1; var costText = new Text2("-" + self.codeLinesCost + " lines\n-" + self.vibePointsCost + " VP", { size: 50, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0.5); self.addChild(costText); self.down = function (x, y, obj) { if (gameState.vibePoints >= self.vibePointsCost) { startBugFix(this); } }; return self; }); var SyntaxBug = Bug.expand(function () { var self = Bug.call(this); self.type = 'syntax'; // Add jagged red visual self.color = 0xFF0000; self.effect = function () { gameState.codeLines *= 0.9; // Reduce code generation }; return self; }); var LogicBug = Bug.expand(function () { var self = Bug.call(this); self.type = 'logic'; // Add methodical blue visual self.color = 0x4A86E8; self.effect = function () { gameState.vibePoints = Math.floor(gameState.vibePoints * 0.5); // Halve vibe points }; return self; }); var Card = Container.expand(function (type, promptText, codeLines, vibePoints, contextImpact, bugChance) { var self = Container.call(this); self.type = type || 'basic'; self.promptText = promptText || "Just a vibe, you know?"; self.codeLines = codeLines || 10; self.vibePoints = vibePoints || 1; self.contextImpact = contextImpact || 5; self.bugChance = bugChance || 0.2; // Card state tracking self.isDragging = false; self.isScaled = false; // Add preview mode properties self.previewMode = false; self.holdTimer = null; self.holdDuration = 300; // .5 seconds self.previewScale = 2.5; // Card background var cardBg = self.attachAsset('card', { anchorX: 0.5, anchorY: 0.5 }); // Card text self.titleText = new Text2(self.type.toUpperCase(), { size: 55, fill: 0x000000 }); self.titleText.anchor.set(0.5, 0); self.titleText.x = 0; self.titleText.y = -220; self.addChild(self.titleText); self.promptTextObj = new Text2(self.promptText, { size: 45, fill: 0x000000 }); self.promptTextObj.anchor.set(0.5, 0); self.promptTextObj.x = 0; self.promptTextObj.y = -160; self.promptTextObj.width = 350; self.addChild(self.promptTextObj); // Card stats var statsText = "Code Lines: " + self.codeLines + "\n" + "Vibe Points: " + self.vibePoints + "\n" + "Context Impact: " + self.contextImpact + "\n" + "Bug Chance: " + Math.round(self.bugChance * 100) + "%"; self.statsTextObj = new Text2(statsText, { size: 45, fill: 0x000000 }); self.statsTextObj.anchor.set(0.5, 0); self.statsTextObj.x = 0; self.statsTextObj.y = 50; self.addChild(self.statsTextObj); // Individual card touch handlers are removed as they are handled globally by game.down, game.move, game.up self.update = function () { // Only move towards target position if NOT in preview mode if (!self.previewMode && !self.isDragging) { // Smoothly move toward target position (if this was in the original update) self.x = self.x + (self.targetX - self.x) * 0.2; self.y = self.y + (self.targetY - self.y) * 0.2; } }; return self; }); var CodeGenerator = Container.expand(function () { var self = Container.call(this); // Store lines of pseudo code that have been typed self.displayedText = ""; // Queue of code lines to generate self.codeQueue = []; // Reference to the text display element self.textDisplay = null; // Reference to cursor element self.cursor = null; // Character typing delay - reduced for faster animation self.charDelay = 20; // Current typing timer self.typingTimer = null; // Current line being typed self.currentLine = ""; // Current position in line self.currentPos = 0; // Set text display reference self.setTextDisplay = function (textElement, cursorElement) { self.textDisplay = textElement; self.cursor = cursorElement; }; // Add a line of code to generate self.addCodeLine = function (lineText) { self.codeQueue.push(lineText); if (!self.typingTimer) { self.typeNextLine(); } }; // Generate multiple lines based on card type and code lines self.generateCodeFromCard = function (card) { // Clear any existing text self.displayedText = ""; self.updateDisplay(); // Add initial comment line self.addCodeLine("// " + card.type.toUpperCase() + " IMPLEMENTATION"); // Generate pseudo code based on card type and lines if (card.type === "UI") { self.addCodeLine("function renderUI() {"); self.addCodeLine(" const elements = createElements();"); self.addCodeLine(" applyStyles(elements);"); self.addCodeLine(" return elements;"); self.addCodeLine("}"); } else if (card.type === "Database") { self.addCodeLine("class DatabaseManager {"); self.addCodeLine(" constructor() {"); self.addCodeLine(" this.connection = initDB();"); self.addCodeLine(" }"); self.addCodeLine(" query(sql) { /* ... */ }"); self.addCodeLine("}"); } else if (card.type === "API") { self.addCodeLine("async function fetchData() {"); self.addCodeLine(" const response = await fetch('/api');"); self.addCodeLine(" return response.json();"); self.addCodeLine("}"); } else if (card.type === "Security") { self.addCodeLine("function authenticate(user) {"); self.addCodeLine(" const token = generateToken(user);"); self.addCodeLine(" return validateAccess(token);"); self.addCodeLine("}"); } else if (card.type === "refactor") { self.addCodeLine("// Cleaning up code structure"); self.addCodeLine("function refactorModule() {"); self.addCodeLine(" removeDuplication();"); self.addCodeLine(" improveNaming();"); self.addCodeLine("}"); } else if (card.type === "debug") { self.addCodeLine("// Bug fixing process"); self.addCodeLine("console.log('Finding issues...');"); self.addCodeLine("debugger;"); self.addCodeLine("fixBugs();"); } else { // Generic code for other card types self.addCodeLine("function implement" + card.type + "() {"); self.addCodeLine(" // TODO: Implementation"); self.addCodeLine(" return success;"); self.addCodeLine("}"); } }; // Start typing the next line in the queue self.typeNextLine = function () { if (self.codeQueue.length === 0) { self.typingTimer = null; return; } self.currentLine = self.codeQueue.shift(); self.currentPos = 0; self.typeNextChar(); }; // Type the next character in the current line self.typeNextChar = function () { if (self.currentPos < self.currentLine.length) { // Add next character self.displayedText += self.currentLine.charAt(self.currentPos); self.currentPos++; self.updateDisplay(); // Schedule next character self.typingTimer = LK.setTimeout(self.typeNextChar, self.charDelay); } else { // Line complete, add newline self.displayedText += "\n"; self.updateDisplay(); // Schedule next line - reduced delay multiplier self.typingTimer = LK.setTimeout(self.typeNextLine, self.charDelay * 2); } }; // Update the displayed text self.updateDisplay = function () { if (self.textDisplay) { self.textDisplay.setText(self.displayedText); // Position cursor at end of text if (self.cursor) { var textWidth = self.displayedText.split("\n").pop().length * 15; var lines = self.displayedText.split("\n").length - 1; self.cursor.x = self.textDisplay.x + textWidth - 41; // Move cursor left by 2% of screen width (2048 * 0.02) self.cursor.y = self.textDisplay.y + lines * 30; } } }; return self; }); var DayIndicator = Container.expand(function () { var self = Container.call(this); var circle = self.attachAsset('dayIndicator', { anchorX: 0.5, anchorY: 0.5 }); self.dayText = new Text2("DAY\n1", { size: 65, fill: 0xFFFFFF }); self.dayText.anchor.set(0.5, 0.5); self.addChild(self.dayText); self.updateDay = function (day) { self.dayText.setText("DAY\n" + day); // Pulse animation tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 300 }); } }); }; return self; }); var MenuButton = Container.expand(function (text, callback) { var self = Container.call(this); var buttonBg = self.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2(text, { size: 55, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.down = function (x, y, obj) { tween(self, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; self.up = function (x, y, obj) { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { if (callback) { callback(); } } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1e2329 }); /**** * Game Code ****/ // Game constants var MAX_DAYS = 10; var TARGET_CODE_LINES = 800; var MAX_CONTEXT_COLLAPSE = 100; var HAND_SIZE = 5; var MAX_BUGS = 10; // Game state variables var gameState = { day: 1, codeLines: 0, vibePoints: 5, contextCollapse: 0, cardsPlayed: 0, maxCardsPerDay: 3, bugs: 0, phase: 'menu', // 'menu', 'playing', 'dayEnd', 'gameOver' canPlayCard: true, features: { ui: false, database: false, api: false, security: false }, thresholdEffects: { bugChanceModifier: 0, maxCardsModifier: 0, contextMultiplier: 1, vibeCostModifier: 0 } }; // Card position constants var projectAreaY = 2732 * 0.7; // Moved down 10% from 0.6 var handY = 2732 - 400; var deckX = 200; var deckY = handY; // Card templates var cardTemplates = [ // Basic cards { type: 'basic', promptText: "Make it work like that app, you know the one", codeLines: 15, vibePoints: 1, contextImpact: 5, bugChance: 0.2 }, { type: 'basic', promptText: "Just spaghetti code it for now", codeLines: 25, vibePoints: 1, contextImpact: 15, bugChance: 0.4 }, { type: 'basic', promptText: "It should be like... clean and efficient", codeLines: 12, vibePoints: 2, contextImpact: 3, bugChance: 0.1 }, { type: 'basic', promptText: "Use that coding pattern with the factory thing", codeLines: 20, vibePoints: 2, contextImpact: 8, bugChance: 0.2 }, // UI cards { type: 'UI', promptText: "Make it look like Apple but not too much", codeLines: 30, vibePoints: 3, contextImpact: 10, bugChance: 0.2, feature: 'ui' }, { type: 'UI', promptText: "I want that Material Design vibe but more flat", codeLines: 35, vibePoints: 3, contextImpact: 12, bugChance: 0.3, feature: 'ui' }, // Database cards { type: 'Database', promptText: "Store stuff efficiently, you know?", codeLines: 40, vibePoints: 4, contextImpact: 15, bugChance: 0.3, feature: 'database' }, { type: 'Database', promptText: "Like SQL but without actual SQL", codeLines: 45, vibePoints: 4, contextImpact: 20, bugChance: 0.4, feature: 'database' }, // API cards { type: 'API', promptText: "Make endpoints that just work", codeLines: 35, vibePoints: 3, contextImpact: 12, bugChance: 0.25, feature: 'api' }, { type: 'API', promptText: "RESTful but also GraphQL-ish", codeLines: 40, vibePoints: 4, contextImpact: 15, bugChance: 0.3, feature: 'api' }, // Security cards { type: 'Security', promptText: "Make it unhackable please", codeLines: 25, vibePoints: 3, contextImpact: 10, bugChance: 0.2, feature: 'security' }, { type: 'Security', promptText: "Do that OAuth thing everyone uses", codeLines: 30, vibePoints: 3, contextImpact: 12, bugChance: 0.25, feature: 'security' }, // Special cards { type: 'refactor', promptText: "Clean up that spaghetti code, please", codeLines: 5, vibePoints: 2, contextImpact: -20, bugChance: 0.1 }, { type: 'coffee', promptText: "Need caffeine to think straight", codeLines: 0, vibePoints: 3, contextImpact: 0, bugChance: 0 }, { type: 'debug', promptText: "Find and squash all those little bugs", codeLines: -10, vibePoints: 3, contextImpact: -5, bugChance: -0.5 }]; // Current hand and deck of cards var currentHand = []; var cardDeck = []; var discardPile = []; var bugContainer; // UI Elements var statsText; var contextBar; var progressBar; var dayIndicator; var endDayButton; var deckVisual; var codebaseContainer = null; var featuresText; // Declare globally // Initialize the game function initializeGame() { gameState = { day: 1, codeLines: 0, vibePoints: 5, contextCollapse: 0, bugs: 0, cardsPlayed: 0, maxCardsPerDay: 3, phase: 'playing', canPlayCard: true, features: { ui: false, database: false, api: false, security: false }, thresholdEffects: { // Initialize here as well bugChanceModifier: 0, maxCardsModifier: 0, contextMultiplier: 1, vibeCostModifier: 0 }, cardStack: [] // Initialize empty card stack }; // Make sure effects are initialized properly updateContextThresholdEffects(); // Clear existing elements while (game.children.length > 0) { game.removeChild(game.children[0]); } // Reset card collections currentHand = []; cardDeck = []; discardPile = []; // Create background var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChild(background); // Create UI elements createUI(); // Create the stack area var stackArea = createStackArea(); // Store reference to the stack area for hit testing gameState.stackArea = stackArea; // Create bug container bugContainer = new Container(); bugContainer.x = 2048 / 2; bugContainer.y = 500; game.addChild(bugContainer); // Initialize deck initializeDeck(); // Draw initial hand drawHand(); // Update stats display updateStatsDisplay(); // Play background music LK.playMusic('gameMusic'); } // New function to check and apply threshold effects function updateContextThresholdEffects() { // Reset modifiers gameState.thresholdEffects = { bugChanceModifier: 0, maxCardsModifier: 0, contextMultiplier: 1, vibeCostModifier: 0 }; var collapseRatio = gameState.contextCollapse / MAX_CONTEXT_COLLAPSE; // Apply effects based on thresholds (cumulative) if (collapseRatio >= 0.25) { gameState.thresholdEffects.bugChanceModifier += 0.1; } if (collapseRatio >= 0.5) { gameState.thresholdEffects.maxCardsModifier -= 1; } if (collapseRatio >= 0.75) { gameState.thresholdEffects.contextMultiplier = 2; } if (collapseRatio >= 0.9) { gameState.thresholdEffects.vibeCostModifier += 1; } } function showBugDetection() { // Create glitchy text effect var alertText = new Text2("BUG DETECTED!", { size: 120, fill: 0xFF0000 }); alertText.anchor.set(0.5, 0.5); alertText.x = 2048 / 2; alertText.y = 2732 / 2; game.addChild(alertText); // Add screen shake var originalX = game.x; var originalY = game.y; var shakeIntensity = 20; var shakeDuration = 500; var startTime = Date.now(); var shakeInterval = null; function updateShake() { var elapsed = Date.now() - startTime; if (elapsed < shakeDuration) { game.x = originalX + (Math.random() * 2 - 1) * shakeIntensity; game.y = originalY + (Math.random() * 2 - 1) * shakeIntensity; } else { if (shakeInterval) { LK.clearInterval(shakeInterval); shakeInterval = null; } game.x = originalX; game.y = originalY; if (alertText.parent) { // Check if alertText is still attached before removing game.removeChild(alertText); } } } // Play alarm sound LK.getSound('bugAlert').play(); // Start the shake interval shakeInterval = LK.setInterval(updateShake, 16); // Call roughly 60 times per second // Ensure the shake stops even if interval timing is slightly off LK.setTimeout(function () { if (shakeInterval) { LK.clearInterval(shakeInterval); shakeInterval = null; } game.x = originalX; game.y = originalY; if (alertText.parent) { game.removeChild(alertText); } }, shakeDuration + 50); // Add a small buffer } function createUI() { // Stats display statsText = new Text2("Code Lines: 0 / " + TARGET_CODE_LINES + "\nVibe Points: 5\nBugs: 0/" + MAX_BUGS, { size: 55, fill: 0xFFFFFF }); statsText.anchor.set(0, 0); statsText.x = 150; statsText.y = 150; game.addChild(statsText); // Project title var projectTitle = new Text2("PROJECT: VIBE CODER", { size: 75, fill: 0xFFFFFF }); projectTitle.anchor.set(0.5, 0); projectTitle.x = 2048 / 2; projectTitle.y = 50; game.addChild(projectTitle); // Context collapse bar background var contextBarBg = LK.getAsset('progressBarBg', { anchorX: 0, anchorY: 0.5, x: 224, y: 660, // Moved up by 50 pixels (from 710 to 660) height: 80 // Doubled height from 40 to 80 }); game.addChild(contextBarBg); // Context collapse bar contextBar = LK.getAsset('progressBar', { anchorX: 0, anchorY: 0.5, x: 224, y: 660, // Moved up by 50 pixels (from 710 to 660) width: 0, height: 80 // Doubled height from 40 to 80 }); game.addChild(contextBar); // Context bar label var contextLabel = new Text2("Context Collapse:", { size: 45, fill: 0xFFFFFF }); contextLabel.anchor.set(0.5, 0.5); // Center anchor contextLabel.x = 224 + 1600 / 2; // Center horizontally over the bar contextLabel.y = 660; // Moved up by 50 pixels (from 710 to 660) game.addChild(contextLabel); // Add threshold indicators var thresholds = [0.25, 0.5, 0.75, 0.9]; thresholds.forEach(function (threshold) { // Create vertical line indicator var indicator = new Text2("│", { size: 80, fill: 0xFF0000 }); indicator.anchor.set(0.5, 0.5); indicator.x = 224 + 1600 * threshold; // Position based on bar width indicator.y = 660; // Match context bar y position game.addChild(indicator); // Add percentage text var percentText = new Text2("".concat(threshold * 100, "%"), { size: 35, fill: 0xFF0000 }); percentText.anchor.set(0.5, 1); percentText.x = indicator.x; percentText.y = indicator.y - 45; // Position above the indicator line game.addChild(percentText); }); // Progress bar background var progressBarBg = LK.getAsset('progressBarBg', { anchorX: 0, anchorY: 0.5, x: 224, y: 790, // Moved down 15% (380 + 2732 * 0.15) height: 80 // Doubled height from 40 to 80 }); game.addChild(progressBarBg); // Progress bar progressBar = LK.getAsset('progressBar', { anchorX: 0, anchorY: 0.5, x: 224, y: 790, // Moved down 15% width: 0, height: 80 // Doubled height from 40 to 80 }); game.addChild(progressBar); // Progress bar label var progressLabel = new Text2("Project Progress:", { size: 45, fill: 0xFFFFFF }); progressLabel.anchor.set(0.5, 0.5); // Center anchor progressLabel.x = 224 + 1600 / 2; // Center horizontally over the bar progressLabel.y = 790; // Moved down 15% game.addChild(progressLabel); // Day indicator dayIndicator = new DayIndicator(); dayIndicator.x = 1848; dayIndicator.y = 200; game.addChild(dayIndicator); // End day button endDayButton = new MenuButton("END DAY", endDay); endDayButton.x = 1848; endDayButton.y = 400; game.addChild(endDayButton); // Project area separator var separator = new Text2("───────────────────────────────────────────────", { size: 55, fill: 0xFFFFFF }); separator.anchor.set(0.5, 0.5); separator.x = 2048 / 2; separator.y = projectAreaY; game.addChild(separator); // Project area label var projectAreaLabel = new Text2("PROJECT AREA", { size: 45, fill: 0xFFFFFF }); projectAreaLabel.anchor.set(0.5, 0); projectAreaLabel.x = 2048 / 2; projectAreaLabel.y = projectAreaY - 80; game.addChild(projectAreaLabel); // Features checklist will be added to the vibe display area // Hand area label var handLabel = new Text2("YOUR HAND", { size: 45, fill: 0xFFFFFF }); handLabel.anchor.set(0.5, 0); handLabel.x = 2048 / 2; handLabel.y = handY - 280; game.addChild(handLabel); // Codebase visualization var codebaseContainer = new Container(); codebaseContainer.x = 2048 / 2; codebaseContainer.y = projectAreaY - 200; game.addChild(codebaseContainer); // [Keep all existing UI creation code here unchanged] // Add vibe layer after all existing UI is created // Create a top-level vibe container that sits above everything else var vibeContainer = new Container(); game.addChild(vibeContainer); // This puts it on top of existing UI // Add vibe background var vibeBackground = LK.getAsset('vibebackground', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); vibeContainer.addChild(vibeBackground); // Add vibe core in center var vibeCore = LK.getAsset('vibecore', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 200 // Slightly above center }); vibeContainer.addChild(vibeCore); // Stylized day counter (we can make this more vibe-appropriate later) var vibeDayIndicator = new Text2("DAY " + gameState.day, { size: 75, fill: 0x00ffff // Cyan color for vibe aesthetic }); vibeDayIndicator.anchor.set(0.5, 0.5); vibeDayIndicator.x = 1848; vibeDayIndicator.y = 200; vibeContainer.addChild(vibeDayIndicator); // Stylized end day button var vibeEndDayButton = new MenuButton("END DAY", endDay); vibeEndDayButton.x = 1848; vibeEndDayButton.y = 400; vibeEndDayButton.scale.set(1.2); // Make it slightly larger vibeContainer.addChild(vibeEndDayButton); // Store the container reference in gameState gameState.vibeContainer = vibeContainer; } function initializeDeck() { // Create a copy of all card templates cardDeck = []; // Add multiple copies of each card template to the deck cardTemplates.forEach(function (template) { // Add more basic cards var count = template.type === 'basic' ? 3 : template.type === 'refactor' || template.type === 'coffee' || template.type === 'debug' ? 1 : 2; for (var i = 0; i < count; i++) { cardDeck.push(Object.assign({}, template)); } }); // Shuffle the deck shuffleDeck(cardDeck); } function shuffleDeck(deck) { for (var i = deck.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var _ref = [deck[j], deck[i]]; deck[i] = _ref[0]; deck[j] = _ref[1]; } } function drawHand() { // Only remove cards from display that aren't in the currentHand anymore for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child instanceof Card && currentHand.indexOf(child) === -1 && gameState.cardStack.indexOf(child) === -1 && !child.isDragging) { game.removeChild(child); } } // Check if we need to reshuffle the discard pile if (cardDeck.length < HAND_SIZE - currentHand.length && discardPile.length > 0) { // Add discard pile back to deck and shuffle cardDeck = cardDeck.concat(discardPile); discardPile = []; shuffleDeck(cardDeck); } // Draw up to hand size but don't remove current cards while (currentHand.length < HAND_SIZE && cardDeck.length > 0) { var cardTemplate = cardDeck.pop(); var card = new Card(cardTemplate.type, cardTemplate.promptText, cardTemplate.codeLines, cardTemplate.vibePoints, cardTemplate.contextImpact, cardTemplate.bugChance); // Add feature property if it exists if (cardTemplate.feature) { card.feature = cardTemplate.feature; } currentHand.push(card); game.addChild(card); } // Position cards in hand positionCardsInHand(); } function positionCardsInHand() { var cardWidth = 400; var spacing = 60; // Increased spacing further for wider hand var overlap = 200; // Keep overlap the same for now var centerIndex = Math.floor((currentHand.length - 1) / 2); var fanAngle = 0.09; // Slightly increased rotation for wider fan // Calculate positions with cards closer to center currentHand.forEach(function (card, index) { // Calculate distance from center card (0 to n) var distanceFromCenter = Math.abs(index - centerIndex); // Cards closer to edges move more towards center var compressionFactor = distanceFromCenter * 0.35; // Reduced compression strength var adjustedSpacing = spacing + overlap * compressionFactor; // Calculate x position with compression toward center var centerX = 2048 / 2; var direction = index < centerIndex ? -1 : 1; // Left or right of center if (index === centerIndex) { // Center card card.x = centerX; } else { // Side cards with compression var positionFromCenter = direction * (cardWidth / 2 + adjustedSpacing * distanceFromCenter); card.x = centerX + positionFromCenter; } card.y = handY + Math.abs(index - (currentHand.length - 1) / 2) * 20; // Arc up in middle card.rotation = (index - (currentHand.length - 1) / 2) * fanAngle; // Fan rotation // Animate to new positions with tween tween(card, { x: card.x, y: card.y, rotation: card.rotation }, { duration: 300, easing: tween.easeOutQuad }); // Update target and original positions card.targetX = card.x; card.targetY = card.y; card.originalX = card.x; card.originalY = card.y; card.originalRotation = card.rotation; card.isDragging = false; }); } function playCard(card) { if (currentHand.indexOf(card) === -1) { return; } if (gameState.cardsPlayed >= gameState.maxCardsPerDay) { // Return card to hand position card.targetX = card.originalX; card.targetY = card.originalY; return; } // Check if player has enough vibe points (including threshold cost) var vibeCost = Math.max(0, -card.vibePoints + gameState.thresholdEffects.vibeCostModifier); // Vibe points are added, so cost is the negative value if (gameState.vibePoints < vibeCost) { // Return card to hand position card.targetX = card.originalX; card.targetY = card.originalY; return; } // Apply all game state changes gameState.vibePoints += card.vibePoints; // Still apply the card's base points gameState.vibePoints -= vibeCost; // Deduct the calculated cost (handles modifier) gameState.codeLines += card.codeLines; // Apply context impact with multiplier gameState.contextCollapse += card.contextImpact * gameState.thresholdEffects.contextMultiplier; gameState.contextCollapse = Math.max(0, Math.min(gameState.contextCollapse, MAX_CONTEXT_COLLAPSE)); // Immediately update effects after context change updateContextThresholdEffects(); if (card.feature) { gameState.features[card.feature] = true; } LK.getSound('cardPlace').play(); // Generate code in console when a card with code lines is played if (card.codeLines > 0 && gameState.stackArea && gameState.stackArea.codeGenerator) { // Animate console to highlight it var consoleBg = gameState.stackArea.children[0].children[0]; tween(consoleBg, { alpha: 1.0, scaleX: 1.05, scaleY: 1.05 }, { duration: 300, onFinish: function onFinish() { tween(consoleBg, { alpha: 0.8, scaleX: 1.0, scaleY: 1.0 }, { duration: 300 }); } }); // Generate code based on card type gameState.stackArea.codeGenerator.generateCodeFromCard(card); } // Remove from hand var index = currentHand.indexOf(card); if (index > -1) { currentHand.splice(index, 1); // Add to discard pile data (but keep the card visual) discardPile.push({ type: card.type, promptText: card.promptText, codeLines: card.codeLines, vibePoints: card.vibePoints, contextImpact: card.contextImpact, bugChance: card.bugChance, feature: card.feature }); } gameState.cardsPlayed++; // Position the card in the stack with slight offset based on stack size var stackPosition = gameState.cardStack.length; var offsetX = stackPosition * 5 - 10; // Small horizontal offset var offsetY = stackPosition * -10; // Stack cards upward // Animate card to stack position tween(card, { x: gameState.stackArea.x + offsetX, y: gameState.stackArea.y + offsetY, scaleX: 0.8, scaleY: 0.8 }, { duration: 300, onFinish: function onFinish() { // Add to stack AFTER animation completes gameState.cardStack.push(card); checkForBugs(card.bugChance); updateStatsDisplay(); positionCardsInHand(); if (currentHand.length < HAND_SIZE) { drawHand(); } checkGameState(); } }); } function updateCodebaseVisualization() { if (!codebaseContainer) { return; } // Clear existing visualization while (codebaseContainer.children.length > 0) { codebaseContainer.removeChild(codebaseContainer.children[0]); } // Calculate how many code blocks to show based on current code lines var totalBlocks = Math.min(20, Math.floor(gameState.codeLines / 50)); // Create blocks for (var i = 0; i < totalBlocks; i++) { var block = new Container(); // Create a code block shape var blockShape = new Sprite(); blockShape.width = 50; blockShape.height = 30; blockShape.color = Math.random() > 0.5 ? 0x4a86e8 : 0x34a853; block.addChild(blockShape); // Position in a grid or pattern block.x = i % 10 * 60 - 270; block.y = Math.floor(i / 10) * 40 - 20; codebaseContainer.addChild(block); } } // Create a Stack area where cards are played function createStackArea() { // Create stack container var stackContainer = new Container(); stackContainer.x = 2048 / 2; stackContainer.y = projectAreaY - 450; // Create background for the stack area using a shape asset var stackBg = LK.getAsset('card', { anchorX: 0.5, anchorY: 0.5, width: 450, height: 550, color: 0x1a1f26 // Slightly lighter than background }); stackBg.alpha = 0.5; stackContainer.addChild(stackBg); // Stack label var stackLabel = new Text2("THE STACK", { size: 45, fill: 0xFFFFFF }); stackLabel.anchor.set(0.5, 0); stackLabel.y = -250; stackContainer.addChild(stackLabel); // Simple border using Text2 with underscores and pipes var topBorder = new Text2("┌────────────────────────────┐", { size: 30, fill: 0x4a86e8 }); topBorder.anchor.set(0.5, 0.5); topBorder.y = -260; stackContainer.addChild(topBorder); var bottomBorder = new Text2("└────────────────────────────┘", { size: 30, fill: 0x4a86e8 }); bottomBorder.anchor.set(0.5, 0.5); bottomBorder.y = 260; stackContainer.addChild(bottomBorder); // Side borders for (var i = -220; i <= 220; i += 40) { var leftBorder = new Text2("│", { size: 30, fill: 0x4a86e8 }); leftBorder.anchor.set(0.5, 0.5); leftBorder.x = -225; leftBorder.y = i; stackContainer.addChild(leftBorder); var rightBorder = new Text2("│", { size: 30, fill: 0x4a86e8 }); rightBorder.anchor.set(0.5, 0.5); rightBorder.x = 225; rightBorder.y = i; stackContainer.addChild(rightBorder); } game.addChild(stackContainer); // Add code console on left: var codeConsole = new Container(); codeConsole.x = -750 + 2048 * 0.02; // Move right by 2% of screen width codeConsole.y = -136 + 2732 * 0.02; // Move down by 2% of screen height var consoleBg = LK.getAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 473, // Increased by 5% (450 * 1.05) height: 688, // Increased by 10% (625 * 1.10) color: 0x000000, alpha: 0.8 }); codeConsole.addChild(consoleBg); var codeText = new Text2("", { size: 30, fill: 0x00FF00 }); codeText.x = -221; // -180 - (2048 * 0.02) codeText.y = -230; codeConsole.addChild(codeText); // Add blinking cursor var cursor = new Text2("_", { size: 30, fill: 0x00FF00 }); cursor.x = codeText.x; // Match updated codeText position cursor.y = codeText.y; codeConsole.addChild(cursor); // Blink cursor LK.setInterval(function () { cursor.visible = !cursor.visible; }, 500); stackContainer.addChild(codeConsole); // Create code generator and attach to stack area var codeGenerator = new CodeGenerator(); codeGenerator.setTextDisplay(codeText, cursor); stackContainer.codeGenerator = codeGenerator; // Add vibe points display on right, mirroring the code console position: var vibeDisplay = new Container(); vibeDisplay.x = 750 - 2048 * 0.02; // Mirror console's horizontal offset from center vibeDisplay.y = -136 + 2732 * 0.02; // Match console's vertical offset var vibeBg = LK.getAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 473, // Match console background width height: 688, // Match console background height color: 0x4a86e8, alpha: 0.2 }); vibeDisplay.addChild(vibeBg); // Add features checklist inside the vibe display featuresText = new Text2("Required Features:\n□ UI Framework\n□ Database\n□ API Integration\n□ Security", { size: 35, // Slightly smaller to fit fill: 0xFFFFFF, align: 'left', wordWrap: true, wordWrapWidth: vibeBg.width * 0.9 // Fit within the background }); featuresText.anchor.set(0, 0); // Anchor top-left featuresText.x = -vibeBg.width / 2 + 30; // Position inside the vibeBg featuresText.y = -vibeBg.height / 2 + 30; vibeDisplay.addChild(featuresText); stackContainer.addChild(vibeDisplay); return stackContainer; } function startBugFix(bug) { var gameContainer = new Container(); gameContainer.x = 2048 / 2; gameContainer.y = 2732 / 2; game.addChild(gameContainer); // Add background panel var panel = LK.getAsset('menuButton', { width: 800, height: 600, color: 0x1a1f26, anchorX: 0.5, anchorY: 0.5 }); gameContainer.addChild(panel); // Add title var title = new Text2(bug instanceof SyntaxBug ? "Fix Syntax Errors!" : "Place Debug Breakpoints!", { size: 55, fill: 0xFFFFFF }); title.anchor.set(0.5, 0.5); title.y = -250; gameContainer.addChild(title); // Add instructions var instructions = new Text2(bug instanceof SyntaxBug ? "Click on the typos in the code to fix them" : "Place exactly 3 breakpoints to catch the bug", { size: 35, fill: 0xFFFFFF }); instructions.anchor.set(0.5, 0.5); instructions.y = -180; gameContainer.addChild(instructions); if (bug instanceof SyntaxBug) { // Syntax bug mini-game with doubled sizes var codeLines = ["function brokenCode() {", " reutrn 'Hello World'", // Typo " cosole.log('Done');", // Typo "}"]; // Double the panel size panel.width = 1600; panel.height = 1200; var errorPositions = [[1, 2], [2, 2]]; // Position of errors in code var foundErrors = 0; // Progress indicator with larger font var progress = new Text2("Errors found: 0/2", { size: 70, // Doubled from 35 fill: 0xFFFFFF }); progress.anchor.set(0.5, 0.5); progress.y = 300; // Doubled from 150 gameContainer.addChild(progress); // Display code with larger font and spacing codeLines.forEach(function (line, index) { var codeLine = new Text2(line, { size: 90, // Doubled from 45 fill: 0xFFFFFF }); codeLine.anchor.set(0, 0); codeLine.x = -600; // Doubled from -300 codeLine.y = index * 100 - 200; // Doubled spacing and offset // Make the hit area for the whole line var hitArea = new Container(); // Use a simple shape for hit area, 'menuButton' asset might not be ideal if we want it truly invisible and just for area detection var hitBox = LK.getAsset('menuButton', { // Using menuButton for simplicity as requested, could be a basic shape too width: 1200, // Wide enough for the full line height: 90, // Match text height color: 0x000000, // Color doesn't matter much if alpha is low alpha: 0.01 // Nearly invisible, but still interactive }); hitArea.addChild(hitBox); hitArea.x = codeLine.x; // Align hitArea with codeLine visually hitArea.y = codeLine.y; hitArea.interactive = true; hitArea.down = function (x, y, obj) { // Calculate character position based on local x within the hit area. // 'x' is already the local coordinate relative to the hitArea. var localX = x; var charPos = Math.floor(localX / 40); // Adjusted char width estimate for size 90 font // Check if click is near an error position for the corresponding line index var isErrorClick = errorPositions.some(function (pos) { return pos[0] === index && Math.abs(pos[1] - charPos) < 2; }); if (isErrorClick && codeLine.fill !== 0x00FF00) { // Check the Text2 object's color foundErrors++; progress.setText("Errors found: ".concat(foundErrors, "/2")); codeLine.fill = 0x00FF00; // Change text color to green hitArea.interactive = false; // Disable further clicks on this line's hit area LK.getSound('cardPlace').play(); // Feedback sound if (foundErrors >= errorPositions.length) { bugFixSuccess(bug, gameContainer); } } }; gameContainer.addChild(hitArea); // Add hit area first gameContainer.addChild(codeLine); // Add text line on top }); // Adjust title and instructions size and position (modifying existing variables) title.size = 110; // Doubled from 55 title.y = -500; // Doubled from -250 instructions.size = 70; // Doubled from 35 instructions.y = -360; // Doubled from -180 // Adjust close button (modifying existing variable) // Note: 'closeButton' is defined later in the function, this modification happens *before* its definition in the original flow. // This code needs to be applied *after* closeButton is created. // Let's modify the closeButton properties right after its creation instead. // --- The modification code for closeButton will be handled in a separate change_block --- } else if (bug instanceof LogicBug) { // Logic bug mini-game var gridSize = 5; var grid = new Container(); var breakpointCount = 0; // Progress indicator var progress = new Text2("Breakpoints: 0/3", { size: 70, // Match syntax bug size fill: 0xFFFFFF }); progress.anchor.set(0.5, 0.5); progress.y = 300; // Match syntax bug position gameContainer.addChild(progress); for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { var cell = LK.getAsset('menuButton', { width: 120, // Doubled from 60 height: 120, // Doubled from 60 color: 0x666666, // Lighter gray for inactive cells anchorX: 0.5, anchorY: 0.5 }); cell.x = (i - (gridSize - 1) / 2) * 140; // Doubled spacing from 70, adjusted centering cell.y = (j - (gridSize - 1) / 2) * 140; // Doubled spacing from 70, adjusted centering cell.interactive = true; cell.isBreakpoint = false; cell.down = function () { if (!this.isBreakpoint) { if (breakpointCount < 3) { // Ensure we don't exceed 3 this.color = 0xFF0000; // Changed to red for active breakpoints this.isBreakpoint = true; breakpointCount++; LK.getSound('cardPlace').play(); } } else { this.color = 0x666666; // Back to gray when deactivated this.isBreakpoint = false; breakpointCount--; } progress.setText("Breakpoints: " + breakpointCount + "/3"); if (breakpointCount === 3) { // Introduce a slight delay before success to see the last breakpoint LK.setTimeout(function () { bugFixSuccess(bug, gameContainer); }, 200); } }; grid.addChild(cell); } } // Adjust grid container position slightly if needed to center it within the doubled panel grid.y = 50; // You might need to adjust this based on visual testing with the doubled panel size gameContainer.addChild(grid); } // Add close button (Give Up) var closeButton = new MenuButton("GIVE UP", function () { // Add a fade out effect for the mini-game container tween(gameContainer, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { if (gameContainer && gameContainer.parent) { gameContainer.parent.removeChild(gameContainer); gameContainer.destroy(); } } }); }); // Adjust close button scale and position conditionally for SyntaxBug if (bug instanceof SyntaxBug) { closeButton.scale.set(1.0); // Doubled from 0.5 closeButton.x = 600; // Doubled from 300 (Position relative to larger panel) closeButton.y = -500; // Doubled from -250 (Align with larger title position) } else { closeButton.scale.set(0.5); // Keep original scale for LogicBug closeButton.x = 300; // Original position closeButton.y = -250; // Original position } gameContainer.addChild(closeButton); // Animate the mini-game appearance gameContainer.alpha = 0; gameContainer.scale.set(0.8); tween(gameContainer, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300 }); } function checkLogicSolution(grid, bug, gameContainer) { // Count placed breakpoints var breakpoints = 0; grid.children.forEach(function (cell) { if (cell.color === 0x4A86E8) { breakpoints++; } }); // Need 3 breakpoints to solve if (breakpoints === 3) { bugFixSuccess(bug, gameContainer); } } function bugFixSuccess(bug, gameContainer) { // Remove vibe points cost gameState.vibePoints -= bug.vibePointsCost; // Remove code lines cost gameState.codeLines -= bug.codeLinesCost; // Decrement bug count gameState.bugs--; // Play success sound LK.getSound('bugFix').play(); // Remove bug with effect - check if bug still exists and has a parent if (bug && bug.parent) { tween(bug, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 300, onFinish: function onFinish() { if (bug && bug.parent) { bug.parent.removeChild(bug); bug.destroy(); } } }); } // Remove mini-game tween(gameContainer, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { if (gameContainer && gameContainer.parent) { gameContainer.parent.removeChild(gameContainer); gameContainer.destroy(); } } }); // Update stats updateStatsDisplay(); } function checkForBugs(bugChance) { // Adjust bug chance based on context collapse and threshold effect var adjustedBugChance = bugChance + gameState.contextCollapse / MAX_CONTEXT_COLLAPSE * 0.3 + gameState.thresholdEffects.bugChanceModifier; // Special case for debug card if (bugChance < 0) { // Reduce bugs by a fixed amount var bugsToRemove = Math.min(gameState.bugs, Math.abs(Math.floor(bugChance * 10))); for (var i = 0; i < bugsToRemove; i++) { if (bugContainer.children.length > 0) { var bug = bugContainer.children[bugContainer.children.length - 1]; bugContainer.removeChild(bug); bug.destroy(); } } gameState.bugs -= bugsToRemove; return; } // Roll for bug if (Math.random() < adjustedBugChance && gameState.bugs < MAX_BUGS) { // Show detection sequence first showBugDetection(); // Create either a syntax or logic bug var bug = Math.random() < 0.5 ? new SyntaxBug() : new LogicBug(); // Position randomly in the project area (within bugContainer's space) bug.x = Math.random() * 1600 - 800; // -800 to 800 (relative to bugContainer center) bug.y = Math.random() * 400 - 200; // -200 to 200 (relative to bugContainer center) bugContainer.addChild(bug); gameState.bugs++; // Apply bug's effect immediately bug.effect(); // Play bug sound LK.getSound('bugAppear').play(); // Animate bug appearance bug.scale.set(0); tween(bug, { scaleX: 1, scaleY: 1 }, { duration: 300 }); } } function updateStatsDisplay() { // Create effects text var effectsText = ""; if (gameState.thresholdEffects.bugChanceModifier > 0) { effectsText += "\nIncreased Bug Chance!"; } if (gameState.thresholdEffects.maxCardsModifier < 0) { effectsText += "\nReduced Cards Per Day!"; } if (gameState.thresholdEffects.contextMultiplier > 1) { effectsText += "\nDouble Context Impact!"; } if (gameState.thresholdEffects.vibeCostModifier > 0) { effectsText += "\nIncreased Vibe Costs!"; } // Update stats text with effects statsText.setText("Code Lines: " + gameState.codeLines + " / " + TARGET_CODE_LINES + "\nVibe Points: " + gameState.vibePoints + "\nBugs: " + gameState.bugs + "/" + MAX_BUGS + "\nCards: " + gameState.cardsPlayed + "/" + Math.max(1, gameState.maxCardsPerDay + gameState.thresholdEffects.maxCardsModifier) + (effectsText ? "\n" + effectsText : "")); // Update context bar var contextWidth = gameState.contextCollapse / MAX_CONTEXT_COLLAPSE * 1600; tween(contextBar, { width: contextWidth }, { duration: 300 }); // Update progress bar var progressWidth = Math.min(gameState.codeLines / TARGET_CODE_LINES, 1) * 1600; tween(progressBar, { width: progressWidth }, { duration: 300 }); // Update features checklist text using the global reference var featuresStatus = "Required Features:\n" + (gameState.features.ui ? "☑" : "□") + " UI Framework\n" + (gameState.features.database ? "☑" : "□") + " Database\n" + (gameState.features.api ? "☑" : "□") + " API Integration\n" + (gameState.features.security ? "☑" : "□") + " Security"; if (featuresText) { featuresText.setText(featuresStatus); } updateCodebaseVisualization(); // [Keep all existing update code] // Update vibe day indicator if it exists if (gameState.vibeContainer) { // Find the day indicator in the vibe container's children var vibeDayIndicator = gameState.vibeContainer.children.find(function (child) { return child instanceof Text2 && child.text.startsWith("DAY"); }); if (vibeDayIndicator) { vibeDayIndicator.setText("DAY " + gameState.day); } } } function checkGameState() { // Update threshold effects first updateContextThresholdEffects(); // Check for game over conditions if (gameState.bugs >= MAX_BUGS) { showGameOver("Too many bugs! Your project crashed!"); return; } if (gameState.contextCollapse >= MAX_CONTEXT_COLLAPSE) { showGameOver("Context collapse! Your AI forgot what it was doing!"); return; } // Check if player can play any more cards *this day* // Adjust max cards per day based on threshold effect var adjustedMaxCards = gameState.maxCardsPerDay + gameState.thresholdEffects.maxCardsModifier; var canPlayMoreCardsThisDay = gameState.cardsPlayed < Math.max(1, adjustedMaxCards); // Ensure at least 1 card can be played // Update card visual states based on whether they can be played this day currentHand.forEach(function (card) { if (!canPlayMoreCardsThisDay) { // Optional: Add visual indicator that cards can't be played card.alpha = 0.7; // Dim the cards } else { card.alpha = 1.0; // Ensure cards are fully visible if playable } }); // Determine if *any* card in hand is playable currently (based on daily limit and having cards) var canPlayAnyCardCurrently = false; if (canPlayMoreCardsThisDay && currentHand.length > 0) { // If within daily limit and hand is not empty, player can potentially play a card. // (Add resource checks here if needed in the future) canPlayAnyCardCurrently = true; } gameState.canPlayCard = canPlayAnyCardCurrently; // Update the global state // Check if player needs to end their day automatically (stuck condition) // This happens if they *cannot* play any card currently AND have no way to draw more cards. if (!canPlayAnyCardCurrently && cardDeck.length === 0 && discardPile.length === 0) { endDay(); } } function endDay() { if (gameState.day >= MAX_DAYS) { // Final evaluation evaluateProject(); } else { // Advance to next day gameState.day++; dayIndicator.updateDay(gameState.day); // Play day change sound LK.getSound('dayChange').play(); // Animate stack cards flying away gameState.cardStack.forEach(function (card, index) { tween(card, { x: 2048 + 300, y: 300 + index * 30, rotation: 0.3, alpha: 0 }, { duration: 500, delay: index * 50, onFinish: function onFinish() { game.removeChild(card); card.destroy(); } }); }); // Clear the stack gameState.cardStack = []; // Discard current hand currentHand.forEach(function (card) { discardPile.push({ type: card.type, promptText: card.promptText, codeLines: card.codeLines, vibePoints: card.vibePoints, contextImpact: card.contextImpact, bugChance: card.bugChance, feature: card.feature }); game.removeChild(card); card.destroy(); }); currentHand = []; // Reset for new day gameState.cardsPlayed = 0; gameState.contextCollapse = Math.max(0, gameState.contextCollapse - 10); // Update threshold effects after reducing context collapse updateContextThresholdEffects(); // Draw new hand drawHand(); // Update stats updateStatsDisplay(); } } function evaluateProject() { var featureCount = (gameState.features.ui ? 1 : 0) + (gameState.features.database ? 1 : 0) + (gameState.features.api ? 1 : 0) + (gameState.features.security ? 1 : 0); var codeProgress = gameState.codeLines / TARGET_CODE_LINES; // Calculate score (out of 100) var score = codeProgress * 50 + featureCount * 10 + Math.max(0, 10 - gameState.bugs) * 2; score = Math.round(score); // Set the final score LK.setScore(score); if (score >= 80) { showYouWin("Project Success! Score: " + score + "/100"); } else if (score >= 50) { showGameOver("Project Submitted With Issues. Score: " + score + "/100"); } else { showGameOver("Project Failed! Score: " + score + "/100"); } } function showYouWin(message) { // Show win message var messageText = new Text2(message, { size: 75, fill: 0xFFFFFF }); messageText.anchor.set(0.5, 0.5); messageText.x = 2048 / 2; messageText.y = 2732 / 2 - 100; game.addChild(messageText); // Add some delay before showing game win LK.setTimeout(function () { LK.showYouWin(); }, 2000); } function showGameOver(message) { // Show game over message var messageText = new Text2(message, { size: 75, fill: 0xFFFFFF }); messageText.anchor.set(0.5, 0.5); messageText.x = 2048 / 2; messageText.y = 2732 / 2 - 100; game.addChild(messageText); // Add some delay before showing game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } function showMainMenu() { // Clear existing elements while (game.children.length > 0) { game.removeChild(game.children[0]); } // Create background var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChild(background); // Title var titleText = new Text2("VIBE CODER", { size: 135, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 600; game.addChild(titleText); // Subtitle var subtitleText = new Text2("The AI Coding Simulator", { size: 75, fill: 0x4A86E8 }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2; subtitleText.y = 700; game.addChild(subtitleText); // Description var descText = new Text2("Build a project in 10 days using vague AI prompts.\nBalance code lines, vibe points, and technical debt.\nAvoid bugs and context collapse!", { size: 55, fill: 0xFFFFFF }); descText.anchor.set(0.5, 0.5); descText.x = 2048 / 2; descText.y = 900; game.addChild(descText); // Start button var startButton = new MenuButton("START GAME", initializeGame); startButton.x = 2048 / 2; startButton.y = 1200; game.addChild(startButton); // Play music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.3, duration: 1000 } }); } game.update = function () { // Skip updates if game isn't in playing state if (gameState.phase !== 'playing') { return; } // Update all cards for smooth movement this.children.forEach(function (child) { if (child instanceof Card && child.update) { child.update(); } }); // Can add other game updates here like: // - Animations // - Visual effects // - Game state checks }; // Game drag state var dragNode = null; var draggedCard = null; var dragOffsetX = 0; var dragOffsetY = 0; var dragStartX = 0; var dragStartY = 0; // Global move handler // Game event handlers // In the down handler, modify how the preview mode works: game.down = function (x, y, obj) { // Reset drag tracking dragStartX = x; dragStartY = y; // Find clicked card var clickedCard = null; for (var i = 0; i < currentHand.length; i++) { var card = currentHand[i]; var dx = x - card.x; var dy = y - card.y; if (Math.abs(dx) < 200 && Math.abs(dy) < 250) { clickedCard = card; break; } } if (clickedCard && gameState.phase === 'playing') { draggedCard = clickedCard; dragOffsetX = clickedCard.x - x; dragOffsetY = clickedCard.y - y; // Store original values draggedCard.originalX = draggedCard.x; draggedCard.originalY = draggedCard.y; // Set up preview timer draggedCard.holdTimer = LK.setTimeout(function () { // Only preview if we haven't moved much from start position var dx = x - dragStartX; var dy = y - dragStartY; var distance = Math.sqrt(dx * dx + dy * dy); if (!draggedCard.isDragging && distance < 10) { // Set preview mode draggedCard.previewMode = true; // Move card up by a fixed amount var previewY = draggedCard.originalY - 600; // Apply scale and move up in same tween tween(draggedCard, { scaleX: draggedCard.previewScale, scaleY: draggedCard.previewScale, y: previewY }, { duration: 300 }); // Bring to front game.setChildIndex(draggedCard, game.children.length - 1); } }, draggedCard.holdDuration); // Set initial target position draggedCard.targetX = draggedCard.x; draggedCard.targetY = draggedCard.y; // Bring to front game.setChildIndex(draggedCard, game.children.length - 1); } }; // In the move handler game.move = function (x, y, obj) { if (draggedCard) { // Calculate distance moved var dx = x - dragStartX; var dy = y - dragStartY; var distance = Math.sqrt(dx * dx + dy * dy); // If we've moved significantly, cancel preview and start drag if (distance > 40) { // Cancel preview mode and timer if (draggedCard.holdTimer) { LK.clearTimeout(draggedCard.holdTimer); draggedCard.holdTimer = null; } // If in preview mode, exit it first with a tween if (draggedCard.previewMode) { draggedCard.previewMode = false; tween(draggedCard, { scaleX: 1, scaleY: 1, y: draggedCard.originalY // Return to original Y while scaling down }, { duration: 150, onFinish: function onFinish() { // Only start dragging after scale tween completes draggedCard.isDragging = true; // Update position after scale reset draggedCard.x = x + dragOffsetX; draggedCard.y = y + dragOffsetY; draggedCard.targetX = draggedCard.x; draggedCard.targetY = draggedCard.y; } }); return; // Exit early while transitioning from preview } // Normal drag handling if not in preview mode if (!draggedCard.isDragging) { draggedCard.isDragging = true; } // Direct 1:1 movement - set actual position, not just target draggedCard.x = x + dragOffsetX; draggedCard.y = y + dragOffsetY; // Also update target position for consistency draggedCard.targetX = draggedCard.x; draggedCard.targetY = draggedCard.y; } } }; // In the up handler game.up = function (x, y, obj) { if (draggedCard) { var cardToEndInteraction = draggedCard; // Store reference locally // Clear any pending preview timer if (cardToEndInteraction.holdTimer) { LK.clearTimeout(cardToEndInteraction.holdTimer); cardToEndInteraction.holdTimer = null; } if (cardToEndInteraction.previewMode) { // End preview mode - return to original position and scale tween(cardToEndInteraction, { scaleX: 1, scaleY: 1, y: cardToEndInteraction.originalY }, { duration: 300, onFinish: function onFinish() { if (cardToEndInteraction) { cardToEndInteraction.previewMode = false; } } }); cardToEndInteraction.isDragging = false; } else if (cardToEndInteraction.isDragging) { // Handle card drop // Check if card is dropped on the stack area var stackAreaX = 2048 / 2; var stackAreaY = projectAreaY - 450; // Simple rectangular hit testing if (Math.abs(x - stackAreaX) < 225 && Math.abs(y - stackAreaY) < 275) { // Card dropped on the stack playCard(cardToEndInteraction); } else { // Return card to hand position cardToEndInteraction.targetX = cardToEndInteraction.originalX; cardToEndInteraction.targetY = cardToEndInteraction.originalY; } cardToEndInteraction.isDragging = false; } // Nullify the global reference draggedCard = null; } }; // Initialize with main menu showMainMenu();
===================================================================
--- original.js
+++ change.js
@@ -1492,8 +1492,19 @@
if (featuresText) {
featuresText.setText(featuresStatus);
}
updateCodebaseVisualization();
+ // [Keep all existing update code]
+ // Update vibe day indicator if it exists
+ if (gameState.vibeContainer) {
+ // Find the day indicator in the vibe container's children
+ var vibeDayIndicator = gameState.vibeContainer.children.find(function (child) {
+ return child instanceof Text2 && child.text.startsWith("DAY");
+ });
+ if (vibeDayIndicator) {
+ vibeDayIndicator.setText("DAY " + gameState.day);
+ }
+ }
}
function checkGameState() {
// Update threshold effects first
updateContextThresholdEffects();
vibebeat1
Music
vibebeat2
Music
vibebeat3
Music
vibebeat4
Music
vibebeat5
Music
vibebeat6
Music
buttonsound
Sound effect
endday
Sound effect
startsound
Sound effect
bugsquish
Sound effect
conceptbutton
Sound effect
wheelstart
Sound effect
wheelspin
Sound effect
wheelstop
Sound effect
keytype
Sound effect