User prompt
Update with: self.move = function (x, y, obj) { if (self.holdTimer && (Math.abs(x - self.dragStartX) > 10 || Math.abs(y - self.dragStartY) > 10)) { LK.clearTimeout(self.holdTimer); self.holdTimer = null; if (!self.isScaled) { self.isDragging = true; self.parent.setChildIndex(self, self.parent.children.length - 1); // Initialize both positions to the same spot trueCard.x = x + self.dragOffsetX; trueCard.y = y + self.dragOffsetY; self.x = trueCard.x; self.y = trueCard.y; } } if (self.isDragging) { // Update true position to exactly match finger trueCard.x = x + self.dragOffsetX; trueCard.y = y + self.dragOffsetY; // Visible card smoothly follows true position var dx = trueCard.x - self.x; var dy = trueCard.y - self.y; self.x += dx * SMOOTH_FACTOR; self.y += dy * SMOOTH_FACTOR; // Bounds checking on both positions trueCard.x = Math.max(200, Math.min(trueCard.x, 2048 - 200)); trueCard.y = Math.max(200, Math.min(trueCard.y, 2732 - 200)); self.x = Math.max(200, Math.min(self.x, 2048 - 200)); self.y = Math.max(200, Math.min(self.y, 2732 - 200)); } };
Code edit (1 edits merged)
Please save this source code
User prompt
Update with: self.move = function (x, y, obj) { if (self.holdTimer && (Math.abs(x - self.dragStartX) > 10 || Math.abs(y - self.dragStartY) > 10)) { LK.clearTimeout(self.holdTimer); self.holdTimer = null; if (!self.isScaled) { self.isDragging = true; self.parent.setChildIndex(self, self.parent.children.length - 1); // Set initial position exactly where the finger is lastX = x + self.dragOffsetX; lastY = y + self.dragOffsetY; self.x = lastX; self.y = lastY; } } if (self.isDragging) { // New exact position where the card should be var newX = x + self.dragOffsetX; var newY = y + self.dragOffsetY; // Set position exactly where finger is self.x = newX; self.y = newY; // Store this position lastX = newX; lastY = newY; // Bounds checking self.x = Math.max(200, Math.min(self.x, 2048 - 200)); self.y = Math.max(200, Math.min(self.y, 2732 - 200)); } };
Code edit (2 edits merged)
Please save this source code
User prompt
Update with: self.move = function (x, y, obj) { if (self.holdTimer && (Math.abs(x - self.dragStartX) > 10 || Math.abs(y - self.dragStartY) > 10)) { LK.clearTimeout(self.holdTimer); self.holdTimer = null; if (!self.isScaled) { self.isDragging = true; self.parent.setChildIndex(self, self.parent.children.length - 1); visualOffsetX = 0; visualOffsetY = 0; } } if (self.isDragging) { // True position follows finger exactly var trueX = x + self.dragOffsetX; var trueY = y + self.dragOffsetY; // Smooth out the visual offset visualOffsetX = visualOffsetX * (1 - SMOOTH_FACTOR); visualOffsetY = visualOffsetY * (1 - SMOOTH_FACTOR); // Apply true position plus smoothed offset self.x = trueX + visualOffsetX; self.y = trueY + visualOffsetY; // Bounds checking self.x = Math.max(200, Math.min(self.x, 2048 - 200)); self.y = Math.max(200, Math.min(self.y, 2732 - 200)); } };
Code edit (5 edits merged)
Please save this source code
User prompt
Update with: self.move = function (x, y, obj) { if (self.holdTimer && (Math.abs(x - self.dragStartX) > 10 || Math.abs(y - self.dragStartY) > 10)) { LK.clearTimeout(self.holdTimer); self.holdTimer = null; if (!self.isScaled) { self.isDragging = true; self.parent.setChildIndex(self, self.parent.children.length - 1); // Initialize current position when starting drag currentX = self.x; currentY = self.y; } } if (self.isDragging) { // Calculate target position var targetX = x + self.dragOffsetX; var targetY = y + self.dragOffsetY; // Update current position to catch up with finger currentX = targetX; currentY = targetY; // Smooth the visual position self.x = self.x + (currentX - self.x) * SMOOTH_FACTOR; self.y = self.y + (currentY - self.y) * SMOOTH_FACTOR; // Bounds checking self.x = Math.max(200, Math.min(self.x, 2048 - 200)); self.y = Math.max(200, Math.min(self.y, 2732 - 200)); } };
Code edit (1 edits merged)
Please save this source code
User prompt
Update with: self.move = function (x, y, obj) { if (self.holdTimer && (Math.abs(x - self.dragStartX) > 10 || Math.abs(y - self.dragStartY) > 10)) { LK.clearTimeout(self.holdTimer); self.holdTimer = null; if (!self.isScaled) { self.isDragging = true; self.parent.setChildIndex(self, self.parent.children.length - 1); } } if (self.isDragging) { targetX = x + self.dragOffsetX; targetY = y + self.dragOffsetY; // Smooth movement self.x = self.x + (targetX - self.x) * SMOOTH_FACTOR; self.y = self.y + (targetY - self.y) * SMOOTH_FACTOR; // Bounds checking self.x = Math.max(200, Math.min(self.x, 2048 - 200)); self.y = Math.max(200, Math.min(self.y, 2732 - 200)); } };
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'return setTimeout(callback, 1000 / 60);' Line Number: 80
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'return setTimeout(callback, 1000 / 60);' Line Number: 80
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'return setTimeout(callback, 1000 / 60);' Line Number: 80
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'requestedFrame = requestAnimationFrame(function () {' Line Number: 150
User prompt
Update as needed with: self.up = function (x, y, obj) { if (requestedFrame) { cancelAnimationFrame(requestedFrame); requestedFrame = null; } // ... rest of existing up handler };
User prompt
Update with: self.move = function (x, y, obj) { // Store the latest position lastX = x; lastY = y; // If we already have a frame requested, don't request another if (requestedFrame) return; // Request frame for smooth animation requestedFrame = requestAnimationFrame(function() { requestedFrame = null; if (self.holdTimer && (Math.abs(lastX - self.dragStartX) > 10 || Math.abs(lastY - self.dragStartY) > 10)) { LK.clearTimeout(self.holdTimer); self.holdTimer = null; if (!self.isScaled) { self.isDragging = true; self.parent.setChildIndex(self, self.parent.children.length - 1); } } if (self.isDragging) { self.x = lastX + self.dragOffsetX; self.y = lastY + self.dragOffsetY; self.x = Math.max(200, Math.min(self.x, 2048 - 200)); self.y = Math.max(200, Math.min(self.y, 2732 - 200)); } }); };
Code edit (1 edits merged)
Please save this source code
User prompt
Update as needed with: self.move = function (x, y, obj) { // Throttle move updates var now = Date.now(); if (now - lastMoveTime < MOVE_THROTTLE) return; lastMoveTime = now; // Rest of the existing move logic stays exactly the same if (self.holdTimer && (Math.abs(x - self.dragStartX) > 10 || Math.abs(y - self.dragStartY) > 10)) { LK.clearTimeout(self.holdTimer); self.holdTimer = null; if (!self.isScaled) { self.isDragging = true; self.parent.setChildIndex(self, self.parent.children.length - 1); } } if (self.isDragging) { self.x = x + self.dragOffsetX; self.y = y + self.dragOffsetY; self.x = Math.max(200, Math.min(self.x, 2048 - 200)); self.y = Math.max(200, Math.min(self.y, 2732 - 200)); } };
Code edit (14 edits merged)
Please save this source code
User prompt
Update with: self.move = function (x, y, obj) { // If the hold timer exists and we've moved more than 5px (reduced from 10), // clear it and start dragging if (self.holdTimer && (Math.abs(x - self.dragStartX) > 5 || Math.abs(y - self.dragStartY) > 5)) { LK.clearTimeout(self.holdTimer); self.holdTimer = null; // Start dragging only if not already scaled if (!self.isScaled) { self.isDragging = true; // Bring to front self.parent.setChildIndex(self, self.parent.children.length - 1); } } // Update position only if dragging if (self.isDragging) { // Direct position updates without any easing self.x = x + self.dragOffsetX; self.y = y + self.dragOffsetY; // Bounds checking after position is set self.x = Math.max(200, Math.min(self.x, 2048 - 200)); self.y = Math.max(200, Math.min(self.y, 2732 - 200)); } };
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: applyCardEffects is not defined' in or related to this line: 'applyCardEffects(self);' Line Number: 140
Code edit (5 edits merged)
Please save this source code
User prompt
add drag and drop for the cards into the project area. they dont need to be animated there, let the player drag them
Code edit (1 edits merged)
Please save this source code
/**** * 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) { // Fix bug gameState.codeLines -= self.codeLinesCost; gameState.vibePoints -= self.vibePointsCost; gameState.bugs--; LK.getSound('bugFix').play(); updateStatsDisplay(); // Remove bug with effect tween(self, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.parent.removeChild(self); self.destroy(); } }); } }; 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 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); self.down = function (x, y, obj) { if (!self.isDragging && gameState.phase === 'playing') { // Set starting position to detect if actual dragging occurs self.startDragX = x; self.startDragY = y; // Set flag for potential drag self.potentialDrag = true; // Calculate offsets self.dragOffsetX = x - self.x; self.dragOffsetY = y - self.y; // Scale up slightly to indicate selection tween(self, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200 }); // IMPORTANT: Don't set isDragging here - wait for move } }; self.up = function (x, y, obj) { // Clear potential drag state self.potentialDrag = false; if (self.isDragging) { self.isDragging = false; // Clear the global dragNode if (dragNode === self) { dragNode = null; } tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200 }); // Check if card was dropped on the project area if (y < projectAreaY && gameState.canPlayCard) { playCard(self); } else { // Return to hand tween(self, { x: self.originalX, y: self.originalY }, { duration: 300 }); } } else { // FIX: Just a click, NOT a play event tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200 }); // Return to original position if needed if (self.x !== self.originalX || self.y !== self.originalY) { tween(self, { x: self.originalX, y: self.originalY }, { duration: 200 }); } } }; 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, bugs: 0, phase: 'menu', // 'menu', 'playing', 'dayEnd', 'gameOver' canPlayCard: true, features: { ui: false, database: false, api: false, security: false } }; // Card position constants var projectAreaY = 2732 * 0.6; var handY = 2732 - 300; 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; // Initialize the game function initializeGame() { gameState = { day: 1, codeLines: 0, vibePoints: 5, contextCollapse: 0, bugs: 0, phase: 'playing', canPlayCard: true, features: { ui: false, database: false, api: false, security: false } }; // 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 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'); } 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: 300 }); game.addChild(contextBarBg); // Context collapse bar contextBar = LK.getAsset('progressBar', { anchorX: 0, anchorY: 0.5, x: 224, y: 300, width: 0 }); game.addChild(contextBar); // Context bar label var contextLabel = new Text2("Context Collapse:", { size: 45, fill: 0xFFFFFF }); contextLabel.anchor.set(0, 0.5); contextLabel.x = 150; contextLabel.y = 300; game.addChild(contextLabel); // Progress bar background var progressBarBg = LK.getAsset('progressBarBg', { anchorX: 0, anchorY: 0.5, x: 224, y: 380 }); game.addChild(progressBarBg); // Progress bar progressBar = LK.getAsset('progressBar', { anchorX: 0, anchorY: 0.5, x: 224, y: 380, width: 0 }); game.addChild(progressBar); // Progress bar label var progressLabel = new Text2("Project Progress:", { size: 45, fill: 0xFFFFFF }); progressLabel.anchor.set(0, 0.5); progressLabel.x = 150; progressLabel.y = 380; 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 var featuresText = new Text2("Required Features:\n□ UI Framework\n□ Database\n□ API Integration\n□ Security", { size: 45, fill: 0xFFFFFF }); featuresText.anchor.set(0, 0); featuresText.x = 1600; featuresText.y = 150; game.addChild(featuresText); // Deck visual deckVisual = LK.getAsset('deck', { anchorX: 0.5, anchorY: 0.5, x: deckX, y: deckY }); game.addChild(deckVisual); // Deck label var deckLabel = new Text2("DECK", { size: 45, fill: 0xFFFFFF }); deckLabel.anchor.set(0.5, 0); deckLabel.x = deckX; deckLabel.y = deckY + 270; game.addChild(deckLabel); // 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); } 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 && !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); // Animate the deck tween(deckVisual, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { tween(deckVisual, { scaleX: 1, scaleY: 1 }, { duration: 300 }); } }); } // 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 = 50; var totalWidth = currentHand.length * cardWidth + (currentHand.length - 1) * spacing; var startX = (2048 - totalWidth) / 2 + cardWidth / 2; currentHand.forEach(function (card, index) { card.x = startX + index * (cardWidth + spacing); card.y = handY; card.originalX = card.x; card.originalY = card.y; card.isDragging = false; }); } function playCard(card) { // Make sure the card exists in hand first if (currentHand.indexOf(card) === -1) { return; // Don't play cards not in hand } // Deduct vibe points cost gameState.vibePoints += card.vibePoints; // Update code lines gameState.codeLines += card.codeLines; // Update context collapse gameState.contextCollapse += card.contextImpact; if (gameState.contextCollapse < 0) { gameState.contextCollapse = 0; } if (gameState.contextCollapse > MAX_CONTEXT_COLLAPSE) { gameState.contextCollapse = MAX_CONTEXT_COLLAPSE; } // Add feature if card has one if (card.feature) { gameState.features[card.feature] = true; } // Play card sound LK.getSound('cardPlace').play(); // Remove card from hand var index = currentHand.indexOf(card); if (index > -1) { currentHand.splice(index, 1); // Add to discard pile discardPile.push({ type: card.type, promptText: card.promptText, codeLines: card.codeLines, vibePoints: card.vibePoints, contextImpact: card.contextImpact, bugChance: card.bugChance, feature: card.feature }); } // Animate card to center then remove tween(card, { x: 2048 / 2, y: projectAreaY - 150, alpha: 0 }, { duration: 500, onFinish: function onFinish() { game.removeChild(card); card.destroy(); // Check for bugs checkForBugs(card.bugChance); // Update stats updateStatsDisplay(); // Only reposition and draw new cards after the animation is complete // First reposition remaining cards positionCardsInHand(); // Then draw a new card if needed if (currentHand.length < HAND_SIZE) { drawHand(); } // Check win/loss conditions 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); } } function checkForBugs(bugChance) { // Adjust bug chance based on context collapse var adjustedBugChance = bugChance + gameState.contextCollapse / MAX_CONTEXT_COLLAPSE * 0.3; // 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) { // Create a new bug var bug = new Bug(); // 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++; // Play bug sound LK.getSound('bugAppear').play(); // Animate bug appearance bug.scale.set(0); tween(bug, { scaleX: 1, scaleY: 1 }, { duration: 300 }); } } function updateStatsDisplay() { // Update stats text statsText.setText("Code Lines: 0 / " + TARGET_CODE_LINES + "\nVibe Points: " + gameState.vibePoints + "\nBugs: 0/" + MAX_BUGS); // 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 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"; // Find and update features text game.children.forEach(function (child) { if (child instanceof Text2 && child.getText && typeof child.getText === 'function') { var text = child.getText(); if (text && text.includes("Required Features")) { child.setText(featuresStatus); } } }); updateCodebaseVisualization(); } function checkGameState() { // 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 var canPlayAnyCard = false; currentHand.forEach(function (card) { // No vibe point cost constraint since cards give vibe points canPlayAnyCard = true; }); gameState.canPlayCard = canPlayAnyCard; // Check if player needs to end their day if (!canPlayAnyCard && 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(); // 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 = []; // Replenish vibe points gameState.vibePoints = 3; // Reduce context collapse slightly gameState.contextCollapse = Math.max(0, gameState.contextCollapse - 10); // 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: 40, 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 drag state var dragNode = null; // Global move handler function handleMove(x, y, obj) { // Increase the drag threshold distance to prevent accidental drag var MIN_DRAG_DISTANCE = 20; // Check for potential drag cards that haven't started dragging yet if (dragNode === null) { for (var i = 0; i < game.children.length; i++) { var child = game.children[i]; if (child.potentialDrag && (Math.abs(child.startDragX - x) > MIN_DRAG_DISTANCE || Math.abs(child.startDragY - y) > MIN_DRAG_DISTANCE)) { // We've moved enough to consider this a drag child.isDragging = true; dragNode = child; // Bring to front if (child.parent) { var parent = child.parent; parent.removeChild(child); parent.addChild(child); } break; } } } // Move the drag node if it exists and is being dragged if (dragNode && dragNode.isDragging) { dragNode.x = x - dragNode.dragOffsetX; dragNode.y = y - dragNode.dragOffsetY; } } // Game event handlers game.move = handleMove; game.down = function (x, y, obj) { // This is handled by individual card objects }; game.up = function (x, y, obj) { // This is handled by individual card objects }; // Initialize with main menu showMainMenu();
/****
* 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) {
// Fix bug
gameState.codeLines -= self.codeLinesCost;
gameState.vibePoints -= self.vibePointsCost;
gameState.bugs--;
LK.getSound('bugFix').play();
updateStatsDisplay();
// Remove bug with effect
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.parent.removeChild(self);
self.destroy();
}
});
}
};
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 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);
self.down = function (x, y, obj) {
if (!self.isDragging && gameState.phase === 'playing') {
// Set starting position to detect if actual dragging occurs
self.startDragX = x;
self.startDragY = y;
// Set flag for potential drag
self.potentialDrag = true;
// Calculate offsets
self.dragOffsetX = x - self.x;
self.dragOffsetY = y - self.y;
// Scale up slightly to indicate selection
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200
});
// IMPORTANT: Don't set isDragging here - wait for move
}
};
self.up = function (x, y, obj) {
// Clear potential drag state
self.potentialDrag = false;
if (self.isDragging) {
self.isDragging = false;
// Clear the global dragNode
if (dragNode === self) {
dragNode = null;
}
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
// Check if card was dropped on the project area
if (y < projectAreaY && gameState.canPlayCard) {
playCard(self);
} else {
// Return to hand
tween(self, {
x: self.originalX,
y: self.originalY
}, {
duration: 300
});
}
} else {
// FIX: Just a click, NOT a play event
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
// Return to original position if needed
if (self.x !== self.originalX || self.y !== self.originalY) {
tween(self, {
x: self.originalX,
y: self.originalY
}, {
duration: 200
});
}
}
};
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,
bugs: 0,
phase: 'menu',
// 'menu', 'playing', 'dayEnd', 'gameOver'
canPlayCard: true,
features: {
ui: false,
database: false,
api: false,
security: false
}
};
// Card position constants
var projectAreaY = 2732 * 0.6;
var handY = 2732 - 300;
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;
// Initialize the game
function initializeGame() {
gameState = {
day: 1,
codeLines: 0,
vibePoints: 5,
contextCollapse: 0,
bugs: 0,
phase: 'playing',
canPlayCard: true,
features: {
ui: false,
database: false,
api: false,
security: false
}
};
// 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 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');
}
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: 300
});
game.addChild(contextBarBg);
// Context collapse bar
contextBar = LK.getAsset('progressBar', {
anchorX: 0,
anchorY: 0.5,
x: 224,
y: 300,
width: 0
});
game.addChild(contextBar);
// Context bar label
var contextLabel = new Text2("Context Collapse:", {
size: 45,
fill: 0xFFFFFF
});
contextLabel.anchor.set(0, 0.5);
contextLabel.x = 150;
contextLabel.y = 300;
game.addChild(contextLabel);
// Progress bar background
var progressBarBg = LK.getAsset('progressBarBg', {
anchorX: 0,
anchorY: 0.5,
x: 224,
y: 380
});
game.addChild(progressBarBg);
// Progress bar
progressBar = LK.getAsset('progressBar', {
anchorX: 0,
anchorY: 0.5,
x: 224,
y: 380,
width: 0
});
game.addChild(progressBar);
// Progress bar label
var progressLabel = new Text2("Project Progress:", {
size: 45,
fill: 0xFFFFFF
});
progressLabel.anchor.set(0, 0.5);
progressLabel.x = 150;
progressLabel.y = 380;
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
var featuresText = new Text2("Required Features:\n□ UI Framework\n□ Database\n□ API Integration\n□ Security", {
size: 45,
fill: 0xFFFFFF
});
featuresText.anchor.set(0, 0);
featuresText.x = 1600;
featuresText.y = 150;
game.addChild(featuresText);
// Deck visual
deckVisual = LK.getAsset('deck', {
anchorX: 0.5,
anchorY: 0.5,
x: deckX,
y: deckY
});
game.addChild(deckVisual);
// Deck label
var deckLabel = new Text2("DECK", {
size: 45,
fill: 0xFFFFFF
});
deckLabel.anchor.set(0.5, 0);
deckLabel.x = deckX;
deckLabel.y = deckY + 270;
game.addChild(deckLabel);
// 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);
}
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 && !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);
// Animate the deck
tween(deckVisual, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
tween(deckVisual, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
}
});
}
// 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 = 50;
var totalWidth = currentHand.length * cardWidth + (currentHand.length - 1) * spacing;
var startX = (2048 - totalWidth) / 2 + cardWidth / 2;
currentHand.forEach(function (card, index) {
card.x = startX + index * (cardWidth + spacing);
card.y = handY;
card.originalX = card.x;
card.originalY = card.y;
card.isDragging = false;
});
}
function playCard(card) {
// Make sure the card exists in hand first
if (currentHand.indexOf(card) === -1) {
return; // Don't play cards not in hand
}
// Deduct vibe points cost
gameState.vibePoints += card.vibePoints;
// Update code lines
gameState.codeLines += card.codeLines;
// Update context collapse
gameState.contextCollapse += card.contextImpact;
if (gameState.contextCollapse < 0) {
gameState.contextCollapse = 0;
}
if (gameState.contextCollapse > MAX_CONTEXT_COLLAPSE) {
gameState.contextCollapse = MAX_CONTEXT_COLLAPSE;
}
// Add feature if card has one
if (card.feature) {
gameState.features[card.feature] = true;
}
// Play card sound
LK.getSound('cardPlace').play();
// Remove card from hand
var index = currentHand.indexOf(card);
if (index > -1) {
currentHand.splice(index, 1);
// Add to discard pile
discardPile.push({
type: card.type,
promptText: card.promptText,
codeLines: card.codeLines,
vibePoints: card.vibePoints,
contextImpact: card.contextImpact,
bugChance: card.bugChance,
feature: card.feature
});
}
// Animate card to center then remove
tween(card, {
x: 2048 / 2,
y: projectAreaY - 150,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
game.removeChild(card);
card.destroy();
// Check for bugs
checkForBugs(card.bugChance);
// Update stats
updateStatsDisplay();
// Only reposition and draw new cards after the animation is complete
// First reposition remaining cards
positionCardsInHand();
// Then draw a new card if needed
if (currentHand.length < HAND_SIZE) {
drawHand();
}
// Check win/loss conditions
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);
}
}
function checkForBugs(bugChance) {
// Adjust bug chance based on context collapse
var adjustedBugChance = bugChance + gameState.contextCollapse / MAX_CONTEXT_COLLAPSE * 0.3;
// 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) {
// Create a new bug
var bug = new Bug();
// 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++;
// Play bug sound
LK.getSound('bugAppear').play();
// Animate bug appearance
bug.scale.set(0);
tween(bug, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
}
}
function updateStatsDisplay() {
// Update stats text
statsText.setText("Code Lines: 0 / " + TARGET_CODE_LINES + "\nVibe Points: " + gameState.vibePoints + "\nBugs: 0/" + MAX_BUGS);
// 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
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";
// Find and update features text
game.children.forEach(function (child) {
if (child instanceof Text2 && child.getText && typeof child.getText === 'function') {
var text = child.getText();
if (text && text.includes("Required Features")) {
child.setText(featuresStatus);
}
}
});
updateCodebaseVisualization();
}
function checkGameState() {
// 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
var canPlayAnyCard = false;
currentHand.forEach(function (card) {
// No vibe point cost constraint since cards give vibe points
canPlayAnyCard = true;
});
gameState.canPlayCard = canPlayAnyCard;
// Check if player needs to end their day
if (!canPlayAnyCard && 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();
// 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 = [];
// Replenish vibe points
gameState.vibePoints = 3;
// Reduce context collapse slightly
gameState.contextCollapse = Math.max(0, gameState.contextCollapse - 10);
// 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: 40,
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 drag state
var dragNode = null;
// Global move handler
function handleMove(x, y, obj) {
// Increase the drag threshold distance to prevent accidental drag
var MIN_DRAG_DISTANCE = 20;
// Check for potential drag cards that haven't started dragging yet
if (dragNode === null) {
for (var i = 0; i < game.children.length; i++) {
var child = game.children[i];
if (child.potentialDrag && (Math.abs(child.startDragX - x) > MIN_DRAG_DISTANCE || Math.abs(child.startDragY - y) > MIN_DRAG_DISTANCE)) {
// We've moved enough to consider this a drag
child.isDragging = true;
dragNode = child;
// Bring to front
if (child.parent) {
var parent = child.parent;
parent.removeChild(child);
parent.addChild(child);
}
break;
}
}
}
// Move the drag node if it exists and is being dragged
if (dragNode && dragNode.isDragging) {
dragNode.x = x - dragNode.dragOffsetX;
dragNode.y = y - dragNode.dragOffsetY;
}
}
// Game event handlers
game.move = handleMove;
game.down = function (x, y, obj) {
// This is handled by individual card objects
};
game.up = function (x, y, obj) {
// This is handled by individual card objects
};
// Initialize with main menu
showMainMenu();
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