/** * Generate placeholder assets for all 10 levels * Run with: node scripts/generate-placeholders.js */ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const projectRoot = path.join(__dirname, '..'); // Create directories const assetsDir = path.join(projectRoot, 'public', 'assets'); const backdropsDir = path.join(assetsDir, 'backdrops'); const musicDir = path.join(assetsDir, 'music'); // Ensure directories exist fs.mkdirSync(backdropsDir, { recursive: true }); fs.mkdirSync(musicDir, { recursive: true }); // Color palettes for each level const levelPalettes = [ ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8', '#F7DC6F', '#BB8FCE'], // Level 1 - Warm ['#3498DB', '#E74C3C', '#2ECC71', '#F39C12', '#9B59B6', '#1ABC9C', '#E67E22'], // Level 2 - Primary ['#FF1744', '#00E676', '#2979FF', '#FFEA00', '#D500F9', '#00E5FF', '#FF9100'], // Level 3 - Neon ['#8E44AD', '#16A085', '#C0392B', '#F39C12', '#2980B9', '#27AE60', '#D35400'], // Level 4 - Deep ['#FF6F61', '#6B5B95', '#88B04B', '#F7CAC9', '#92A8D1', '#955251', '#B565A7'], // Level 5 - Pastel ['#34495E', '#E74C3C', '#ECF0F1', '#3498DB', '#2ECC71', '#F39C12', '#9B59B6'], // Level 6 - Modern ['#FF4500', '#FFD700', '#00CED1', '#FF1493', '#00FF00', '#1E90FF', '#FF69B4'], // Level 7 - Vibrant ['#8B4513', '#DAA520', '#CD853F', '#D2691E', '#B8860B', '#A0522D', '#DEB887'], // Level 8 - Earth ['#000080', '#4B0082', '#8B008B', '#9400D3', '#9932CC', '#BA55D3', '#DA70D6'], // Level 9 - Purple ['#FF0000', '#FF4500', '#FF6347', '#FF7F50', '#FFA500', '#FFD700', '#FFFF00'] // Level 10 - Fire ]; // Generate backdrop images using Canvas API (Node.js) async function generateBackdrop(level, palette) { const { createCanvas } = await import('canvas'); const canvas = createCanvas(256, 224); const ctx = canvas.getContext('2d'); // Create gradient background const gradient = ctx.createLinearGradient(0, 0, 256, 224); gradient.addColorStop(0, palette[0]); gradient.addColorStop(0.5, palette[1]); gradient.addColorStop(1, palette[2]); ctx.fillStyle = gradient; ctx.fillRect(0, 0, 256, 224); // Add some retro patterns ctx.fillStyle = palette[3]; ctx.globalAlpha = 0.1; for (let i = 0; i < 50; i++) { const x = Math.random() * 256; const y = Math.random() * 224; const size = Math.random() * 20 + 5; ctx.fillRect(x, y, size, size); } // Add level indicator in corner ctx.globalAlpha = 0.3; ctx.fillStyle = palette[4]; ctx.font = 'bold 48px monospace'; ctx.fillText(`L${level}`, 10, 50); // PLAY AREA INDICATOR - Make it very clear // Play area is at x:88, y:32, width:80, height:160 // Dark background for play area ctx.globalAlpha = 0.4; ctx.fillStyle = '#000000'; ctx.fillRect(88, 32, 80, 160); // Bright border around play area ctx.globalAlpha = 1.0; ctx.strokeStyle = '#FFFF00'; // Bright yellow ctx.lineWidth = 3; ctx.strokeRect(88, 32, 80, 160); // Add corner markers for extra visibility ctx.fillStyle = '#FFFF00'; const markerSize = 8; // Top-left corner ctx.fillRect(88 - markerSize, 32 - markerSize, markerSize, markerSize); // Top-right corner ctx.fillRect(88 + 80, 32 - markerSize, markerSize, markerSize); // Bottom-left corner ctx.fillRect(88 - markerSize, 32 + 160, markerSize, markerSize); // Bottom-right corner ctx.fillRect(88 + 80, 32 + 160, markerSize, markerSize); // Add text labels ctx.globalAlpha = 0.8; ctx.fillStyle = '#FFFFFF'; ctx.font = 'bold 10px monospace'; ctx.fillText('PLAY AREA', 92, 28); ctx.fillText('80x160px', 95, 200); ctx.fillText(`(${88},${32})`, 92, 44); // Add grid lines inside play area to show it clearly ctx.globalAlpha = 0.15; ctx.strokeStyle = '#FFFFFF'; ctx.lineWidth = 1; // Vertical lines every 8 pixels (block size) for (let x = 88; x <= 168; x += 8) { ctx.beginPath(); ctx.moveTo(x, 32); ctx.lineTo(x, 192); ctx.stroke(); } // Horizontal lines every 8 pixels for (let y = 32; y <= 192; y += 8) { ctx.beginPath(); ctx.moveTo(88, y); ctx.lineTo(168, y); ctx.stroke(); } return canvas.toBuffer('image/png'); } // Generate silent MP3 placeholder (we'll create a minimal valid MP3) function generateSilentMP3() { // Minimal valid MP3 header for 1 second of silence // This is a simplified approach - in production you'd use a proper audio library const mp3Header = Buffer.from([ 0xFF, 0xFB, 0x90, 0x00, // MP3 sync word and header ]); // Create a small buffer with MP3 frame headers const frames = 38; // Approximately 1 second at 44.1kHz const frameSize = 417; const buffer = Buffer.alloc(frames * frameSize); for (let i = 0; i < frames; i++) { mp3Header.copy(buffer, i * frameSize); } return buffer; } // Main generation function async function generateAllAssets() { console.log('Generating placeholder assets...\n'); // Check if canvas is available let canvasAvailable = false; try { await import('canvas'); canvasAvailable = true; } catch (e) { console.log('⚠️ Canvas module not available. Install with: npm install canvas'); console.log(' Skipping backdrop generation. You can add your own PNG files.\n'); } for (let level = 1; level <= 10; level++) { const levelBackdropDir = path.join(backdropsDir, `level-${level}`); const levelMusicDir = path.join(musicDir, `level-${level}`); fs.mkdirSync(levelBackdropDir, { recursive: true }); fs.mkdirSync(levelMusicDir, { recursive: true }); // Generate backdrop if (canvasAvailable) { const backdropPath = path.join(levelBackdropDir, 'backdrop.png'); const backdropBuffer = await generateBackdrop(level, levelPalettes[level - 1]); fs.writeFileSync(backdropPath, backdropBuffer); console.log(`✓ Generated backdrop for level ${level}`); } else { console.log(`⊘ Skipped backdrop for level ${level} (canvas not available)`); } // Generate silent MP3 const musicPath = path.join(levelMusicDir, 'track.mp3'); const mp3Buffer = generateSilentMP3(); fs.writeFileSync(musicPath, mp3Buffer); console.log(`✓ Generated music placeholder for level ${level}`); } console.log('\n✅ All placeholder assets generated!'); console.log('\nYou can now replace these files with your own:'); console.log(' - Backdrops: public/assets/backdrops/level-X/backdrop.png (256x224 pixels)'); console.log(' - Music: public/assets/music/level-X/track.mp3'); } generateAllAssets().catch(console.error);