{"asset_map": {"turret_tier1": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/turret_tier1_643925fe-2aa5-4b82-a2f9-7c7541182bd9.webp", "type": "image", "prompt": "Generate a top-down 90-degree overhead view of a basic automated turret for a post-apocalyptic defense game. Circular steel platform base in steel blue (#4a90e2) with weathered metal texture and rivets. Single-barrel gun mounted on a rotating base pointing upward. Orange (#ff8c42) warning stripes on the barrel and small orange lights. Stylized, clean outlines, detailed but worn with scratches and rust. Transparent background, professional game-ready asset.", "description": "Basic Tier 1 automated turret with a single-barrel gun and steel blue finish.", "subtype": "character", "aspect_ratio": [818, 870], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "turret_tier2": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/turret_tier2_627b7d4e-ba46-45c6-9f62-b586904132d5.webp", "type": "image", "prompt": "Generate a top-down 90-degree overhead view of an upgraded Tier 2 automated turret. Hexagonal platform base in purple (#9b59b6) with reinforced plating. Dual-barrel gun system pointing upward. Yellow (#f1c40f) glowing energy cores on the sides. Sophisticated mechanical details, smooth surfaces, premium equipment look. Transparent background, stylized post-apocalyptic art style, matching the perspective of turret_tier1.", "description": "Upgraded Tier 2 turret with dual barrels and a purple hexagonal base.", "subtype": "character", "aspect_ratio": [962, 1019], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "turret_tier3": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/turret_tier3_1e9db9b6-e42c-4ea7-adb5-b598ee827d44.webp", "type": "image", "prompt": "Generate a top-down 90-degree overhead view of an elite Tier 3 automated turret. Octagonal armored platform base in red (#e74c3c) with heavy plating. Triple-barrel rotary cannon system. Cyan (#00d4ff) glowing energy shields and plasma elements. Most advanced and powerful defensive design, complex mechanical elements, pristine finish. Transparent background, stylized art style, matching the perspective of turret_tier2.", "description": "Elite Tier 3 turret with a triple-barrel rotary system and red armored base.", "subtype": "character", "aspect_ratio": [963, 1022], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "enemy_basic": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/enemy_basic_fc484a05-9fd7-43e2-86ff-81572daa1b53.webp", "type": "image", "prompt": "Generate a top-down 90-degree overhead view of a basic hostile enemy unit for a post-apocalyptic game. Dull red (#c0392b) primary color with thick dark outlines. Simple, recognizable silhouette of a small post-apocalyptic buggy or crawler creature. Minimal but clear details, front-facing movement indicator, stylized and slightly cartoonish. Transparent background.", "description": "Basic slow enemy unit, dull red hostile vehicle or creature.", "subtype": "character", "aspect_ratio": [694, 974], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "enemy_fast": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/enemy_fast_c0192f4a-ae02-4c38-942b-93aeff3480e0.webp", "type": "image", "prompt": "Generate a top-down 90-degree overhead view of a fast enemy unit. Bright yellow (#f39c12) primary color with dark outlines. Sleek, streamlined, aerodynamic shape suggesting speed. Includes speed indicators like racing stripes or a pointed body. Stylized art style consistent with enemy_basic. Transparent background.", "description": "Fast enemy unit, sleek yellow aerodynamic vehicle or creature.", "subtype": "character", "aspect_ratio": [821, 1148], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "base_structure": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/base_structure_7a3b4572-b8bd-4af5-bb25-884c92c1e4fc.webp", "type": "image", "prompt": "Generate a top-down 90-degree overhead view of a fortified base stronghold. Military green and gray color scheme with rust and wear. Features reinforced walls with metal plating, sandbag barriers, and red/orange warning beacons. Clear entrance at the top. Stylized post-apocalyptic military aesthetic, weathered but strong, high detail. Transparent background.", "description": "The player's fortified base structure with walls and sandbags.", "subtype": "object", "aspect_ratio": [994, 913], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "explosion_particle": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/explosion_particle_95a03fa9-063e-4f90-8fa3-0cd79145d27e.webp", "type": "image", "prompt": "Generate a single 24x24 pixel-style explosion particle. Irregular angular fragment with a gradient from a bright orange/yellow center (#ff8c42) to dark red edges (#e74c3c). Stylized with a slight glow and soft transparent edges for blending. Transparent background.", "description": "A single stylized explosion fragment for hit and death effects.", "subtype": "effect", "aspect_ratio": [698, 763], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "muzzle_flash": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/muzzle_flash_7a321452-21c4-44da-b01e-5593595eb402.webp", "type": "image", "prompt": "Generate a stylized muzzle flash effect. Star-burst/cross pattern radiating from center. Bright white and yellow core with sharp orange outer rays. Energetic and clean. Edges fade to transparent, transparent background.", "description": "Muzzle flash effect for when turrets fire projectiles.", "subtype": "effect", "aspect_ratio": [819, 851], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "currency_coin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/currency_coin_b0af26c4-504f-4d3f-8c87-99be42ce984a.webp", "type": "image", "prompt": "Generate a shiny currency resource icon. Circular or hexagonal coin shape in metallic gold and bronze (#f39c12). Simple gear or star symbol etched in the center. Slightly angled top-down view to show 3D depth, polished game icon style. Transparent background.", "description": "Gold currency coin dropped by enemies.", "subtype": "ui", "aspect_ratio": [954, 948], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "turret_fire_sfx": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/turret_fire_sfx_e36c5797-499a-4150-acf3-73fdacf8b589.mp3", "type": "audio", "prompt": "A sharp, punchy mechanical turret firing sound effect. Quick 'tak' sound followed by a very short high-tech energy hum. 0.3 seconds duration, clean attack, dry texture, suitable for frequent repetition in a top-down defense game.", "description": "Short, punchy mechanical turret firing sound with a slight sci-fi edge.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.4, "loop": false, "animation": null}, "enemy_hit_sfx": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/enemy_hit_sfx_f8e8ccdf-d4da-456e-a4b8-ff9470b9a349.mp3", "type": "audio", "prompt": "Short, crunchy impact sound effect. Metallic 'clink' mixed with a subtle energy burst. High-frequency snap, very fast decay, designed for clear audio feedback during intense combat scenes.", "description": "Sharp impact sound effect providing feedback when projectiles strike enemies.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 2.0, "loop": false, "animation": null}, "enemy_death_sfx": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/enemy_death_sfx_abfe21fb-4dcd-4e1e-9f93-568d2e554ae3.mp3", "type": "audio", "prompt": "Small explosion sound effect with a metallic crunch. Low-end thud followed by a crumbling debris sound. Satisfying and impactful, signifying enemy defeat in a post-apocalyptic setting. 0.5 seconds of active sound.", "description": "Satisfying small explosion sound for enemy destruction.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.21, "loop": false, "animation": null}, "merge_sfx": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/merge_sfx_e5df2ddf-e440-4ab7-9d18-c139c2c4328c.mp3", "type": "audio", "prompt": "A magical and technological transformation sound. Rising pitch synthesis with a 'shimmer' effect. Starts with a mechanical latch and ends with a celebratory high-frequency chime. Rewarding and positive energy.", "description": "Bright, rewarding ascending sound for turret upgrades.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.64, "loop": false, "animation": null}, "purchase_sfx": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/purchase_sfx_6b7e7ee0-9519-4da8-b06c-50f8c3640275.mp3", "type": "audio", "prompt": "Satisfying UI confirmation sound. A heavy mechanical 'clunk' as if a metal structure is locking into place. Solid, grounded, and positive. No reverb, very dry and immediate.", "description": "Mechanical click and construction sound for turret placement.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.21, "loop": false, "animation": null}, "wave_complete_sfx": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/wave_complete_sfx_2154ad11-0d9c-4b21-8866-da232078fba2.mp3", "type": "audio", "prompt": "Short 1.5 second victory fanfare. Upbeat synth melody with a driving electronic percussion kick. Triumphant major key resolution. Energetic and encouraging, signaling successful defense.", "description": "Triumphant short musical fanfare for completing a wave.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.81, "loop": false, "animation": null}, "game_over_sfx": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/game_over_sfx_c3163278-61e4-4842-9e9e-ccd67eb9be34.mp3", "type": "audio", "prompt": "Game over sound effect, dramatic descending digital tones. Ends with a muffled explosion and a low-frequency hum fading out. Conveys loss but remains soft enough to encourage a retry.", "description": "Dramatic descending tone signaling the end of the game.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 2.85, "loop": false, "animation": null}, "background_music": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/background_music_50a1722c-8f2b-45af-97f8-d0bfabaf3af4.mp3", "type": "audio", "prompt": "Post-apocalyptic industrial electronic background music. 130 BPM, driving rhythmic synth bassline, gritty percussion, and atmospheric pads. Tense and strategic mood but energetic. Seamless loop, no vocals, high-quality production for a tower defense game.", "description": "Industrial electronic background track with a driving post-apocalyptic vibe.", "subtype": "music", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 30.0, "loop": true, "animation": null}}, "game_code": "<!DOCTYPE html>\n<html>\n<head>\n    <title>Turret Defend Apocalypse</title>\n    <style>\n        /* CSS Reset and Base Styles */\n        * {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n        }\n\n        @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700;900&family=Inter:wght@400;600&display=swap');\n\n        body, html {\n            width: 100%;\n            height: 100%;\n            overflow: hidden;\n            touch-action: none;\n            -ms-touch-action: none;\n            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n        }\n\n        /* CSS Custom Properties */\n        :root {\n            --transition-fast: 150ms;\n            --transition-normal: 300ms;\n            --transition-slow: 500ms;\n            --ease-out: cubic-bezier(0.0, 0, 0.2, 1);\n            --ease-bounce: cubic-bezier(0.68, -0.6, 0.32, 1.6);\n            --space-xs: 8px;\n            --space-sm: 16px;\n            --space-md: 24px;\n            --space-lg: 32px;\n            --space-xl: 48px;\n        }\n\n        /* Game Container */\n        #game-world {\n            position: relative;\n            width: 100%;\n            height: 100%;\n            background: linear-gradient(180deg, #3d2f1f 0%, #2a2520 100%);\n        }\n\n        #game-canvas {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n        }\n\n        /* UI Overlay */\n        .ui-overlay {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            pointer-events: none;\n            z-index: 10;\n        }\n\n        .ui-overlay > * {\n            pointer-events: auto;\n        }\n\n        /* Top UI Bar */\n        .top-ui {\n            position: absolute;\n            top: 0;\n            left: 0;\n            right: 0;\n            height: 140px;\n            background: linear-gradient(180deg, rgba(26, 26, 26, 0.95) 0%, rgba(26, 26, 26, 0.85) 80%, rgba(26, 26, 26, 0.6) 100%);\n            display: flex;\n            flex-direction: column;\n            padding: var(--space-sm);\n            gap: var(--space-sm);\n            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n        }\n\n        .stat-row {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            gap: var(--space-sm);\n        }\n\n        .stat-item {\n            display: flex;\n            align-items: center;\n            gap: var(--space-xs);\n            color: #ffffff;\n            font-size: 32px;\n            font-weight: 700;\n            font-family: 'Orbitron', monospace;\n        }\n\n        .stat-label {\n            font-size: 16px;\n            color: #999999;\n            font-weight: 400;\n            text-transform: uppercase;\n            letter-spacing: 0.5px;\n            font-family: 'Inter', sans-serif;\n        }\n\n        .currency-value {\n            color: #f39c12;\n            font-size: 36px;\n            text-shadow: 0 0 8px rgba(243, 156, 18, 0.4);\n        }\n\n        .wave-value {\n            color: #4a90e2;\n            font-size: 28px;\n        }\n\n        /* Health Bar */\n        .health-bar-container {\n            width: 100%;\n            height: 36px;\n            background: rgba(0, 0, 0, 0.6);\n            border-radius: 18px;\n            overflow: hidden;\n            border: 2px solid rgba(255, 255, 255, 0.1);\n            box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);\n        }\n\n        .health-bar-fill {\n            height: 100%;\n            background: linear-gradient(90deg, #e74c3c 0%, #c0392b 100%);\n            transition: width var(--transition-normal) var(--ease-out);\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            color: white;\n            font-size: 20px;\n            font-weight: 700;\n            font-family: 'Orbitron', monospace;\n            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\n            position: relative;\n        }\n\n        .health-bar-fill::before {\n            content: '';\n            position: absolute;\n            top: 0;\n            left: 0;\n            right: 0;\n            height: 50%;\n            background: linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, transparent 100%);\n            border-radius: 18px 18px 0 0;\n        }\n\n        /* Game Over Screen */\n        .game-over-screen {\n            position: absolute;\n            top: 0;\n            left: 0;\n            right: 0;\n            bottom: 0;\n            background: rgba(0, 0, 0, 0.9);\n            display: none;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            gap: var(--space-lg);\n            z-index: 100;\n        }\n\n        .game-over-screen.visible {\n            display: flex;\n        }\n\n        .game-over-title {\n            font-size: 72px;\n            font-weight: 900;\n            color: #e74c3c;\n            text-transform: uppercase;\n            letter-spacing: 4px;\n            font-family: 'Orbitron', monospace;\n            text-shadow: 0 0 20px rgba(231, 76, 60, 0.6),\n                         0 4px 8px rgba(0, 0, 0, 0.8);\n        }\n\n        .game-over-stats {\n            display: flex;\n            flex-direction: column;\n            gap: var(--space-sm);\n            align-items: center;\n        }\n\n        .game-over-stat {\n            font-size: 28px;\n            color: #ffffff;\n        }\n\n        .game-over-stat-label {\n            color: #999999;\n            font-size: 22px;\n            text-transform: uppercase;\n            letter-spacing: 0.5px;\n        }\n\n        .game-over-stat-value {\n            color: #4a90e2;\n            font-weight: 700;\n            font-size: 36px;\n            font-family: 'Orbitron', monospace;\n        }\n\n        /* Buttons */\n        .btn {\n            padding: var(--space-md) var(--space-xl);\n            font-size: 32px;\n            font-weight: 700;\n            font-family: 'Orbitron', monospace;\n            border: none;\n            border-radius: 12px;\n            cursor: pointer;\n            transition: all var(--transition-fast) var(--ease-out);\n            text-transform: uppercase;\n            letter-spacing: 2px;\n            min-width: 240px;\n            min-height: 96px;\n        }\n\n        .btn-primary {\n            background: linear-gradient(135deg, #4a90e2 0%, #357abd 100%);\n            color: white;\n            box-shadow: 0 6px 16px rgba(74, 144, 226, 0.5);\n            border: 2px solid rgba(255, 255, 255, 0.2);\n        }\n\n        .btn-primary:hover {\n            transform: translateY(-3px);\n            box-shadow: 0 8px 20px rgba(74, 144, 226, 0.7);\n        }\n\n        .btn-primary:active {\n            transform: translateY(-1px);\n            box-shadow: 0 4px 12px rgba(74, 144, 226, 0.5);\n        }\n\n        .btn-upgrade {\n            position: absolute;\n            bottom: 20px;\n            right: 20px;\n            width: 120px;\n            height: 120px;\n            padding: 0;\n            font-size: 24px;\n            background: linear-gradient(135deg, #00d4ff 0%, #0099cc 100%);\n            color: white;\n            box-shadow: 0 6px 16px rgba(0, 212, 255, 0.5);\n            border: 2px solid rgba(255, 255, 255, 0.3);\n            border-radius: 12px;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            gap: 4px;\n            z-index: 20;\n        }\n\n        .btn-upgrade:hover:not(:disabled) {\n            transform: translateY(-3px);\n            box-shadow: 0 8px 20px rgba(0, 212, 255, 0.7);\n        }\n\n        .btn-upgrade:active:not(:disabled) {\n            transform: translateY(-1px);\n            box-shadow: 0 4px 12px rgba(0, 212, 255, 0.5);\n        }\n\n        .btn-upgrade:disabled {\n            opacity: 0.5;\n            cursor: not-allowed;\n            background: linear-gradient(135deg, #666666 0%, #444444 100%);\n            box-shadow: 0 4px 12px rgba(100, 100, 100, 0.3);\n        }\n\n        /* Wave Transition */\n        .wave-transition {\n            position: absolute;\n            top: 50%;\n            left: 50%;\n            transform: translate(-50%, -50%) scale(0.9);\n            font-size: 56px;\n            font-weight: 900;\n            font-family: 'Orbitron', monospace;\n            color: #4a90e2;\n            text-align: center;\n            pointer-events: none;\n            opacity: 0;\n            transition: all var(--transition-slow) var(--ease-out);\n            text-shadow: 0 0 20px rgba(74, 144, 226, 0.8),\n                         0 4px 8px rgba(0, 0, 0, 0.8);\n            text-transform: uppercase;\n            letter-spacing: 3px;\n        }\n\n        .wave-transition.visible {\n            opacity: 1;\n            transform: translate(-50%, -50%) scale(1);\n        }\n\n        /* Tooltip */\n        .turret-tooltip {\n            position: absolute;\n            background: rgba(26, 26, 26, 0.97);\n            color: white;\n            padding: var(--space-sm);\n            border-radius: 8px;\n            font-size: 20px;\n            pointer-events: none;\n            display: none;\n            z-index: 50;\n            border: 2px solid #4a90e2;\n            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);\n        }\n\n        .turret-tooltip.visible {\n            display: block;\n        }\n\n        .tooltip-row {\n            display: flex;\n            justify-content: space-between;\n            gap: var(--space-lg);\n            margin: 6px 0;\n        }\n\n        .tooltip-label {\n            color: #999999;\n            text-transform: uppercase;\n            font-size: 16px;\n            letter-spacing: 0.5px;\n        }\n\n        .tooltip-value {\n            color: #4a90e2;\n            font-weight: 700;\n            font-family: 'Orbitron', monospace;\n            font-size: 22px;\n        }\n    </style>\n</head>\n<body>\n    <div id=\"game-world\">\n        <canvas id=\"game-canvas\"></canvas>\n        \n        <div class=\"ui-overlay\">\n            <!-- Top UI -->\n            <div class=\"top-ui\">\n                <div class=\"stat-row\">\n                    <div class=\"stat-item\">\n                        <span class=\"stat-label\">Currency:</span>\n                        <span class=\"currency-value\" id=\"currency-display\">0</span>\n                    </div>\n                    <div class=\"stat-item\">\n                        <span class=\"stat-label\">Wave:</span>\n                        <span class=\"wave-value\" id=\"wave-display\">1</span>\n                    </div>\n                </div>\n                <div class=\"health-bar-container\">\n                    <div class=\"health-bar-fill\" id=\"health-bar\">\n                        <span id=\"health-text\">20 / 20</span>\n                    </div>\n                </div>\n            </div>\n\n            <!-- Wave Transition -->\n            <div class=\"wave-transition\" id=\"wave-transition\">\n                Wave 1\n            </div>\n\n            <!-- Turret Tooltip -->\n            <div class=\"turret-tooltip\" id=\"turret-tooltip\">\n                <div class=\"tooltip-row\">\n                    <span class=\"tooltip-label\">Tier:</span>\n                    <span class=\"tooltip-value\" id=\"tooltip-tier\">1</span>\n                </div>\n                <div class=\"tooltip-row\">\n                    <span class=\"tooltip-label\">Damage:</span>\n                    <span class=\"tooltip-value\" id=\"tooltip-damage\">10</span>\n                </div>\n                <div class=\"tooltip-row\">\n                    <span class=\"tooltip-label\">Range:</span>\n                    <span class=\"tooltip-value\" id=\"tooltip-range\">150</span>\n                </div>\n            </div>\n\n            <!-- Laser Upgrade Button -->\n            <button class=\"btn btn-upgrade\" id=\"laser-upgrade-btn\">\n                \u26a1 LASER<br><span style=\"font-size: 20px;\">$50</span>\n            </button>\n\n            <!-- Game Over Screen -->\n            <div class=\"game-over-screen\" id=\"game-over-screen\">\n                <div class=\"game-over-title\">Game Over</div>\n                <div class=\"game-over-stats\">\n                    <div class=\"game-over-stat\">\n                        <span class=\"game-over-stat-label\">Waves Survived:</span>\n                        <span class=\"game-over-stat-value\" id=\"final-wave\">0</span>\n                    </div>\n                    <div class=\"game-over-stat\">\n                        <span class=\"game-over-stat-label\">Enemies Defeated:</span>\n                        <span class=\"game-over-stat-value\" id=\"final-kills\">0</span>\n                    </div>\n                </div>\n                <button class=\"btn btn-primary\" id=\"restart-btn\">Restart</button>\n            </div>\n        </div>\n    </div>\n\n    <script>\n        /**\n         * TURRET DEFEND APOCALYPSE\n         * \n         * A tactical tower defense game where players build and upgrade turrets to protect\n         * their base from waves of enemies. Features auto-firing turrets, merge mechanics\n         * for upgrades, and escalating difficulty across 15 waves.\n         * \n         * Core Mechanics:\n         * - Place turrets on designated spots using currency\n         * - Merge identical tier turrets to create more powerful versions\n         * - Defend base from two enemy types: Basic (slow) and Fast (quick)\n         * - Survive as many waves as possible\n         */\n\n        async function run(mode) {\n            const gameWorld = document.getElementById('game-world');\n            const canvas = document.getElementById('game-canvas');\n            const ctx = canvas.getContext('2d');\n\n            // Initialize canvas\n            function resizeCanvas() {\n                canvas.width = gameWorld.clientWidth;\n                canvas.height = gameWorld.clientHeight;\n            }\n            resizeCanvas();\n            window.addEventListener('resize', resizeCanvas);\n\n            // Asset cache\n            const assets = {\n                images: {},\n                audio: {}\n            };\n\n            // Audio context\n            const audioContext = new (window.AudioContext || window.webkitAudioContext)();\n            const audioBuffers = {};\n\n            // Preload assets\n            async function preloadAssets() {\n                const imageIds = [\n                    'turret_tier1', 'turret_tier2', 'turret_tier3',\n                    'enemy_basic', 'enemy_fast', 'base_structure',\n                    'explosion_particle', 'muzzle_flash', 'currency_coin'\n                ];\n\n                const audioIds = [\n                    'turret_fire_sfx', 'enemy_hit_sfx', 'enemy_death_sfx',\n                    'merge_sfx', 'purchase_sfx', 'wave_complete_sfx',\n                    'game_over_sfx', 'background_music'\n                ];\n\n                // Load images\n                const imagePromises = imageIds.map(id => {\n                    return new Promise((resolve, reject) => {\n                        const assetInfo = lib.getAsset(id);\n                        if (assetInfo) {\n                            const img = new Image();\n                            img.onload = () => {\n                                assets.images[id] = { img, info: assetInfo };\n                                resolve();\n                            };\n                            img.onerror = reject;\n                            img.src = assetInfo.url;\n                        } else {\n                            resolve();\n                        }\n                    });\n                });\n\n                // Load audio\n                const audioPromises = audioIds.map(id => {\n                    return new Promise(async (resolve, reject) => {\n                        const assetInfo = lib.getAsset(id);\n                        if (assetInfo) {\n                            try {\n                                const response = await fetch(assetInfo.url);\n                                const arrayBuffer = await response.arrayBuffer();\n                                const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n                                audioBuffers[id] = audioBuffer;\n                                assets.audio[id] = assetInfo;\n                                resolve();\n                            } catch (error) {\n                                lib.log(`Failed to load audio ${id}: ${error}`);\n                                resolve();\n                            }\n                        } else {\n                            resolve();\n                        }\n                    });\n                });\n\n                await Promise.all([...imagePromises, ...audioPromises]);\n            }\n\n            // Play sound effect\n            function playSound(id, volume = 1.0) {\n                if (audioBuffers[id]) {\n                    const source = audioContext.createBufferSource();\n                    const gainNode = audioContext.createGain();\n                    source.buffer = audioBuffers[id];\n                    gainNode.gain.value = volume;\n                    source.connect(gainNode);\n                    gainNode.connect(audioContext.destination);\n                    source.start(0);\n                }\n            }\n\n            // Play background music\n            let musicSource = null;\n            function playBackgroundMusic() {\n                if (audioBuffers['background_music'] && !musicSource) {\n                    musicSource = audioContext.createBufferSource();\n                    const gainNode = audioContext.createGain();\n                    musicSource.buffer = audioBuffers['background_music'];\n                    musicSource.loop = true;\n                    gainNode.gain.value = 0.3;\n                    musicSource.connect(gainNode);\n                    gainNode.connect(audioContext.destination);\n                    musicSource.start(0);\n                }\n            }\n\n            await preloadAssets();\n\n            // Game constants\n            const CANVAS_WIDTH = 720;\n            const CANVAS_HEIGHT = 1280;\n            const PLAYABLE_HEIGHT = 1140;\n            const UI_HEIGHT = 140;\n            const PATH_WIDTH = 120;\n            const TURRET_SIZE = 80;\n            const ENEMY_SIZE = 40;\n            const SPOT_SIZE = 100;\n            const LASER_UPGRADE_COST = 50;\n\n            // Turret stats by tier\n            const TURRET_STATS = {\n                1: { damage: 10, range: 150, fireRate: 1.0, cost: 100 },\n                2: { damage: 25, range: 200, fireRate: 0.7, cost: 0 },\n                3: { damage: 60, range: 250, fireRate: 0.5, cost: 0 }\n            };\n\n            // Enemy stats by type\n            const ENEMY_STATS = {\n                basic: { hp: 30, speed: 50, currency: 15 },\n                fast: { hp: 20, speed: 100, currency: 20 }\n            };\n\n            // Path waypoints (curved path from top to bottom)\n            const PATH_WAYPOINTS = [\n                { x: 360, y: 0 },\n                { x: 360, y: 200 },\n                { x: 500, y: 350 },\n                { x: 500, y: 500 },\n                { x: 220, y: 650 },\n                { x: 220, y: 800 },\n                { x: 360, y: 950 },\n                { x: 360, y: 1100 }\n            ];\n\n            // Calculate turret placement spots along the path\n            function calculatePlacementSpots(count) {\n                const spots = [];\n                const segmentCount = Math.floor(count / 2);\n                \n                for (let i = 0; i < segmentCount; i++) {\n                    const t = (i + 1) / (segmentCount + 1);\n                    const pathIndex = Math.floor(t * (PATH_WAYPOINTS.length - 1));\n                    const nextIndex = Math.min(pathIndex + 1, PATH_WAYPOINTS.length - 1);\n                    const localT = (t * (PATH_WAYPOINTS.length - 1)) - pathIndex;\n                    \n                    const x = PATH_WAYPOINTS[pathIndex].x + (PATH_WAYPOINTS[nextIndex].x - PATH_WAYPOINTS[pathIndex].x) * localT;\n                    const y = PATH_WAYPOINTS[pathIndex].y + (PATH_WAYPOINTS[nextIndex].y - PATH_WAYPOINTS[pathIndex].y) * localT;\n                    \n                    // Calculate perpendicular offset\n                    const dx = PATH_WAYPOINTS[nextIndex].x - PATH_WAYPOINTS[pathIndex].x;\n                    const dy = PATH_WAYPOINTS[nextIndex].y - PATH_WAYPOINTS[pathIndex].y;\n                    const length = Math.sqrt(dx * dx + dy * dy);\n                    const perpX = -dy / length;\n                    const perpY = dx / length;\n                    \n                    const offset = PATH_WIDTH / 2 + SPOT_SIZE / 2 + 20;\n                    \n                    // Left spot\n                    spots.push({\n                        x: x + perpX * offset,\n                        y: y + perpY * offset,\n                        turret: null\n                    });\n                    \n                    // Right spot\n                    spots.push({\n                        x: x - perpX * offset,\n                        y: y - perpY * offset,\n                        turret: null\n                    });\n                }\n                \n                return spots;\n            }\n\n            // Game state\n            let gameState = {\n                mode: mode,\n                playing: false,\n                wave: 1,\n                currency: window.gameConfig.startingCurrency,\n                baseHealth: window.gameConfig.baseHealth,\n                maxBaseHealth: window.gameConfig.baseHealth,\n                enemiesDefeated: 0,\n                placementSpots: calculatePlacementSpots(window.gameConfig.placementSpotCount),\n                turrets: [],\n                enemies: [],\n                projectiles: [],\n                particles: [],\n                waveTimer: 0,\n                waveSpawnTimer: 0,\n                waveEnemiesSpawned: 0,\n                waveEnemiesTotal: 0,\n                waveComplete: false,\n                draggedTurret: null,\n                dragStartSpot: null,\n                touchHoldTimer: 0,\n                hoveredSpot: null,\n                laserActive: false\n            };\n\n            // Wave configuration\n            function getWaveConfig(waveNum) {\n                const baseCount = 5 + waveNum * 2;\n                const fastRatio = Math.min(waveNum / 15, 0.5);\n                const fastCount = Math.floor(baseCount * fastRatio);\n                const basicCount = baseCount - fastCount;\n                \n                return {\n                    basicCount: basicCount,\n                    fastCount: fastCount,\n                    spawnInterval: Math.max(1.0 - waveNum * 0.03, 0.3) / window.gameConfig.spawnRateMultiplier,\n                    hpMultiplier: 1 + (waveNum - 1) * 0.1\n                };\n            }\n\n            // Start wave\n            function startWave() {\n                const config = getWaveConfig(gameState.wave);\n                gameState.waveEnemiesTotal = config.basicCount + config.fastCount;\n                gameState.waveEnemiesSpawned = 0;\n                gameState.waveSpawnTimer = 0;\n                gameState.waveComplete = false;\n                gameState.playing = true;\n                \n                // Show wave transition\n                const waveTransition = document.getElementById('wave-transition');\n                waveTransition.textContent = `Wave ${gameState.wave}`;\n                waveTransition.classList.add('visible');\n                setTimeout(() => {\n                    waveTransition.classList.remove('visible');\n                }, 2000);\n            }\n\n            // Spawn enemy\n            function spawnEnemy(type) {\n                const config = getWaveConfig(gameState.wave);\n                const stats = { ...ENEMY_STATS[type] };\n                stats.hp *= config.hpMultiplier;\n                stats.maxHp = stats.hp;\n                \n                const enemy = {\n                    type: type,\n                    x: PATH_WAYPOINTS[0].x + (Math.random() - 0.5) * 20,\n                    y: PATH_WAYPOINTS[0].y,\n                    hp: stats.hp,\n                    maxHp: stats.maxHp,\n                    speed: stats.speed,\n                    currency: stats.currency,\n                    pathProgress: 0,\n                    pathIndex: 0\n                };\n                \n                gameState.enemies.push(enemy);\n            }\n\n            // Update enemy position along path\n            function updateEnemyPosition(enemy, deltaTime) {\n                const currentWaypoint = PATH_WAYPOINTS[enemy.pathIndex];\n                const nextWaypoint = PATH_WAYPOINTS[enemy.pathIndex + 1];\n                \n                if (!nextWaypoint) {\n                    // Reached end\n                    return true;\n                }\n                \n                const dx = nextWaypoint.x - currentWaypoint.x;\n                const dy = nextWaypoint.y - currentWaypoint.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const moveDistance = enemy.speed * deltaTime;\n                \n                enemy.pathProgress += moveDistance / distance;\n                \n                if (enemy.pathProgress >= 1) {\n                    enemy.pathIndex++;\n                    enemy.pathProgress = 0;\n                    \n                    if (enemy.pathIndex >= PATH_WAYPOINTS.length - 1) {\n                        return true;\n                    }\n                }\n                \n                const t = enemy.pathProgress;\n                const newWaypoint = PATH_WAYPOINTS[enemy.pathIndex];\n                const newNextWaypoint = PATH_WAYPOINTS[enemy.pathIndex + 1];\n                \n                enemy.x = newWaypoint.x + (newNextWaypoint.x - newWaypoint.x) * t + (Math.random() - 0.5) * 10;\n                enemy.y = newWaypoint.y + (newNextWaypoint.y - newWaypoint.y) * t;\n                \n                return false;\n            }\n\n            // Create turret\n            function createTurret(spot, tier) {\n                return {\n                    spot: spot,\n                    tier: tier,\n                    x: spot.x,\n                    y: spot.y,\n                    fireTimer: 0,\n                    target: null\n                };\n            }\n\n            // Find target for turret\n            function findTarget(turret) {\n                const stats = TURRET_STATS[turret.tier];\n                let closestEnemy = null;\n                let closestDist = Infinity;\n                \n                for (const enemy of gameState.enemies) {\n                    const dx = enemy.x - turret.x;\n                    const dy = enemy.y - turret.y;\n                    const dist = Math.sqrt(dx * dx + dy * dy);\n                    \n                    if (dist <= stats.range && dist < closestDist) {\n                        closestEnemy = enemy;\n                        closestDist = dist;\n                    }\n                }\n                \n                return closestEnemy;\n            }\n\n            // Fire projectile\n            function fireProjectile(turret, target) {\n                const dx = target.x - turret.x;\n                const dy = target.y - turret.y;\n                const dist = Math.sqrt(dx * dx + dy * dy);\n                \n                gameState.projectiles.push({\n                    x: turret.x,\n                    y: turret.y,\n                    vx: (dx / dist) * 400,\n                    vy: (dy / dist) * 400,\n                    damage: TURRET_STATS[turret.tier].damage,\n                    target: target\n                });\n                \n                playSound('turret_fire_sfx', 0.3);\n                \n                // Muzzle flash particle\n                createParticle(turret.x, turret.y, 'muzzle_flash', 0.1);\n            }\n\n            // Create particle\n            function createParticle(x, y, type, lifetime, vx = 0, vy = 0) {\n                gameState.particles.push({\n                    x: x,\n                    y: y,\n                    type: type,\n                    lifetime: lifetime,\n                    maxLifetime: lifetime,\n                    vx: vx,\n                    vy: vy,\n                    rotation: Math.random() * Math.PI * 2\n                });\n            }\n\n            // Create explosion\n            function createExplosion(x, y) {\n                for (let i = 0; i < 8; i++) {\n                    const angle = (Math.PI * 2 * i) / 8;\n                    const speed = 100 + Math.random() * 100;\n                    createParticle(\n                        x, y, 'explosion_particle', 0.5,\n                        Math.cos(angle) * speed,\n                        Math.sin(angle) * speed\n                    );\n                }\n            }\n\n            // Damage enemy\n            function damageEnemy(enemy, damage) {\n                enemy.hp -= damage;\n                playSound('enemy_hit_sfx', 0.2);\n                \n                if (enemy.hp <= 0) {\n                    // Enemy defeated\n                    gameState.currency += Math.floor(enemy.currency * window.gameConfig.currencyMultiplier);\n                    gameState.enemiesDefeated++;\n                    createExplosion(enemy.x, enemy.y);\n                    playSound('enemy_death_sfx', 0.4);\n                    \n                    // Spawn currency coin\n                    createParticle(enemy.x, enemy.y, 'currency_coin', 0.8, 0, -100);\n                    \n                    return true;\n                }\n                \n                return false;\n            }\n\n            // Check if can merge turrets\n            function canMergeTurrets(turret1, turret2) {\n                return turret1 && turret2 && \n                       turret1 !== turret2 && \n                       turret1.tier === turret2.tier && \n                       turret1.tier < 3;\n            }\n\n            // Merge turrets\n            function mergeTurrets(spot1, spot2) {\n                const turret1 = spot1.turret;\n                const turret2 = spot2.turret;\n                \n                if (canMergeTurrets(turret1, turret2)) {\n                    const newTier = turret1.tier + 1;\n                    \n                    // Remove old turrets\n                    spot1.turret = null;\n                    spot2.turret = null;\n                    \n                    // Create new turret at first spot\n                    spot1.turret = createTurret(spot1, newTier);\n                    \n                    // Effects\n                    createExplosion(spot1.x, spot1.y);\n                    playSound('merge_sfx', 0.6);\n                    \n                    return true;\n                }\n                \n                return false;\n            }\n\n            // Get spot at position\n            function getSpotAt(x, y) {\n                for (const spot of gameState.placementSpots) {\n                    const dx = x - spot.x;\n                    const dy = y - spot.y;\n                    const dist = Math.sqrt(dx * dx + dy * dy);\n                    \n                    if (dist <= SPOT_SIZE / 2) {\n                        return spot;\n                    }\n                }\n                return null;\n            }\n\n            // Use laser upgrade to kill one yellow enemy\n            function useLaserUpgrade() {\n                if (gameState.currency < LASER_UPGRADE_COST) {\n                    return false;\n                }\n\n                // Find first yellow (fast) enemy\n                let targetEnemy = null;\n                for (const enemy of gameState.enemies) {\n                    if (enemy.type === 'fast') {\n                        targetEnemy = enemy;\n                        break;\n                    }\n                }\n\n                if (!targetEnemy) {\n                    return false;\n                }\n\n                // Deduct currency\n                gameState.currency -= LASER_UPGRADE_COST;\n\n                // Kill the enemy\n                gameState.currency += Math.floor(targetEnemy.currency * window.gameConfig.currencyMultiplier);\n                gameState.enemiesDefeated++;\n                createExplosion(targetEnemy.x, targetEnemy.y);\n                playSound('enemy_death_sfx', 0.4);\n\n                // Draw laser effect\n                gameState.laserActive = true;\n                gameState.laserTargetX = targetEnemy.x;\n                gameState.laserTargetY = targetEnemy.y;\n                gameState.laserTimer = 0.2;\n\n                // Remove enemy\n                const index = gameState.enemies.indexOf(targetEnemy);\n                if (index > -1) {\n                    gameState.enemies.splice(index, 1);\n                }\n\n                return true;\n            }\n\n            // Input handling\n            let mousePos = { x: 0, y: 0 };\n            let mouseDown = false;\n            let touchHoldTimer = 0;\n            const TOUCH_HOLD_TIME = 0.3;\n\n            function getCanvasPos(clientX, clientY) {\n                const rect = canvas.getBoundingClientRect();\n                return {\n                    x: (clientX - rect.left) * (canvas.width / rect.width),\n                    y: (clientY - rect.top) * (canvas.height / rect.height)\n                };\n            }\n\n            function handlePointerDown(x, y) {\n                if (gameState.mode !== 'play' || !gameState.playing) return;\n                \n                mouseDown = true;\n                touchHoldTimer = 0;\n                \n                const spot = getSpotAt(x, y);\n                \n                if (spot && spot.turret) {\n                    // Start potential drag\n                    gameState.hoveredSpot = spot;\n                } else if (spot && !spot.turret) {\n                    // Try to purchase turret\n                    if (gameState.currency >= TURRET_STATS[1].cost) {\n                        gameState.currency -= TURRET_STATS[1].cost;\n                        spot.turret = createTurret(spot, 1);\n                        playSound('purchase_sfx', 0.5);\n                    }\n                }\n            }\n\n            function handlePointerMove(x, y) {\n                mousePos = { x, y };\n                \n                if (gameState.mode !== 'play') return;\n                \n                if (mouseDown && gameState.hoveredSpot && gameState.hoveredSpot.turret && !gameState.draggedTurret) {\n                    // Check if moved enough to start drag\n                    const dx = x - gameState.hoveredSpot.x;\n                    const dy = y - gameState.hoveredSpot.y;\n                    const dist = Math.sqrt(dx * dx + dy * dy);\n                    \n                    if (dist > 20 || touchHoldTimer >= TOUCH_HOLD_TIME) {\n                        gameState.draggedTurret = gameState.hoveredSpot.turret;\n                        gameState.dragStartSpot = gameState.hoveredSpot;\n                    }\n                }\n            }\n\n            function handlePointerUp(x, y) {\n                if (gameState.mode !== 'play') return;\n                \n                if (gameState.draggedTurret) {\n                    const targetSpot = getSpotAt(x, y);\n                    \n                    if (targetSpot && targetSpot !== gameState.dragStartSpot) {\n                        if (targetSpot.turret) {\n                            // Try to merge\n                            if (!mergeTurrets(gameState.dragStartSpot, targetSpot)) {\n                                // Can't merge, return to original spot\n                            }\n                        } else {\n                            // Move to empty spot\n                            targetSpot.turret = gameState.draggedTurret;\n                            gameState.dragStartSpot.turret = null;\n                            gameState.draggedTurret.spot = targetSpot;\n                            gameState.draggedTurret.x = targetSpot.x;\n                            gameState.draggedTurret.y = targetSpot.y;\n                        }\n                    }\n                    \n                    gameState.draggedTurret = null;\n                    gameState.dragStartSpot = null;\n                }\n                \n                mouseDown = false;\n                touchHoldTimer = 0;\n                gameState.hoveredSpot = null;\n            }\n\n            // Mouse events\n            canvas.addEventListener('mousedown', (e) => {\n                const pos = getCanvasPos(e.clientX, e.clientY);\n                handlePointerDown(pos.x, pos.y);\n            });\n\n            canvas.addEventListener('mousemove', (e) => {\n                const pos = getCanvasPos(e.clientX, e.clientY);\n                handlePointerMove(pos.x, pos.y);\n            });\n\n            canvas.addEventListener('mouseup', (e) => {\n                const pos = getCanvasPos(e.clientX, e.clientY);\n                handlePointerUp(pos.x, pos.y);\n            });\n\n            // Touch events\n            canvas.addEventListener('touchstart', (e) => {\n                e.preventDefault();\n                const touch = e.touches[0];\n                const pos = getCanvasPos(touch.clientX, touch.clientY);\n                handlePointerDown(pos.x, pos.y);\n            });\n\n            canvas.addEventListener('touchmove', (e) => {\n                e.preventDefault();\n                const touch = e.touches[0];\n                const pos = getCanvasPos(touch.clientX, touch.clientY);\n                handlePointerMove(pos.x, pos.y);\n            });\n\n            canvas.addEventListener('touchend', (e) => {\n                e.preventDefault();\n                handlePointerUp(mousePos.x, mousePos.y);\n            });\n\n            // Restart button\n            document.getElementById('restart-btn').addEventListener('click', () => {\n                // Reset game state\n                gameState.wave = 1;\n                gameState.currency = window.gameConfig.startingCurrency;\n                gameState.baseHealth = window.gameConfig.baseHealth;\n                gameState.maxBaseHealth = window.gameConfig.baseHealth;\n                gameState.enemiesDefeated = 0;\n                gameState.enemies = [];\n                gameState.projectiles = [];\n                gameState.particles = [];\n                gameState.turrets = [];\n                gameState.draggedTurret = null;\n                gameState.dragStartSpot = null;\n                gameState.laserActive = false;\n                \n                // Reset placement spots\n                for (const spot of gameState.placementSpots) {\n                    spot.turret = null;\n                }\n                \n                // Hide game over screen\n                document.getElementById('game-over-screen').classList.remove('visible');\n                \n                // Start new wave\n                startWave();\n                updateUI();\n            });\n\n            // Laser upgrade button\n            const laserBtn = document.getElementById('laser-upgrade-btn');\n            laserBtn.addEventListener('click', () => {\n                if (gameState.mode === 'play' && gameState.playing) {\n                    if (useLaserUpgrade()) {\n                        playSound('turret_fire_sfx', 0.8);\n                    }\n                }\n            });\n\n            // Update UI\n            function updateUI() {\n                document.getElementById('currency-display').textContent = gameState.currency;\n                document.getElementById('wave-display').textContent = gameState.wave;\n                \n                const healthPercent = (gameState.baseHealth / gameState.maxBaseHealth) * 100;\n                document.getElementById('health-bar').style.width = healthPercent + '%';\n                document.getElementById('health-text').textContent = \n                    `${Math.max(0, gameState.baseHealth)} / ${gameState.maxBaseHealth}`;\n                \n                // Update laser button state\n                const laserBtn = document.getElementById('laser-upgrade-btn');\n                const hasYellowEnemies = gameState.enemies.some(e => e.type === 'fast');\n                const canAffordLaser = gameState.currency >= LASER_UPGRADE_COST;\n                \n                laserBtn.disabled = !canAffordLaser || !hasYellowEnemies || !gameState.playing;\n            }\n\n            // Show game over\n            function showGameOver() {\n                gameState.playing = false;\n                document.getElementById('final-wave').textContent = gameState.wave;\n                document.getElementById('final-kills').textContent = gameState.enemiesDefeated;\n                document.getElementById('game-over-screen').classList.add('visible');\n                playSound('game_over_sfx', 0.7);\n            }\n\n            // Draw functions\n            function drawPath() {\n                ctx.strokeStyle = '#2a2a2a';\n                ctx.lineWidth = PATH_WIDTH;\n                ctx.lineCap = 'round';\n                ctx.lineJoin = 'round';\n                \n                ctx.beginPath();\n                ctx.moveTo(PATH_WAYPOINTS[0].x, PATH_WAYPOINTS[0].y);\n                \n                for (let i = 1; i < PATH_WAYPOINTS.length; i++) {\n                    ctx.lineTo(PATH_WAYPOINTS[i].x, PATH_WAYPOINTS[i].y);\n                }\n                \n                ctx.stroke();\n                \n                // Path edges\n                ctx.strokeStyle = '#5a5a5a';\n                ctx.lineWidth = 2;\n                ctx.stroke();\n            }\n\n            function drawBase() {\n                const baseAsset = assets.images['base_structure'];\n                if (baseAsset) {\n                    const baseY = PATH_WAYPOINTS[PATH_WAYPOINTS.length - 1].y;\n                    const baseX = PATH_WAYPOINTS[PATH_WAYPOINTS.length - 1].x;\n                    \n                    const aspectRatio = baseAsset.info.aspect_ratio;\n                    const width = 200;\n                    const height = width * (aspectRatio[1] / aspectRatio[0]);\n                    \n                    ctx.drawImage(\n                        baseAsset.img,\n                        baseX - width / 2,\n                        baseY - height / 2,\n                        width,\n                        height\n                    );\n                }\n            }\n\n            function drawPlacementSpots() {\n                for (const spot of gameState.placementSpots) {\n                    if (!spot.turret) {\n                        // Empty spot\n                        const canAfford = gameState.currency >= TURRET_STATS[1].cost;\n                        ctx.strokeStyle = canAfford ? 'rgba(74, 144, 226, 0.6)' : 'rgba(231, 76, 60, 0.4)';\n                        ctx.lineWidth = 3;\n                        ctx.strokeRect(\n                            spot.x - SPOT_SIZE / 2,\n                            spot.y - SPOT_SIZE / 2,\n                            SPOT_SIZE,\n                            SPOT_SIZE\n                        );\n                        \n                        // Cost indicator\n                        if (gameState.mode === 'play' && gameState.playing) {\n                            ctx.fillStyle = canAfford ? '#4a90e2' : 'rgba(231, 76, 60, 0.8)';\n                            ctx.font = 'bold 24px Orbitron';\n                            ctx.textAlign = 'center';\n                            ctx.textBaseline = 'middle';\n                            ctx.fillText('$' + TURRET_STATS[1].cost, spot.x, spot.y);\n                            \n                            // Add shadow for readability\n                            if (canAfford) {\n                                ctx.shadowColor = 'rgba(74, 144, 226, 0.5)';\n                                ctx.shadowBlur = 8;\n                                ctx.fillText('$' + TURRET_STATS[1].cost, spot.x, spot.y);\n                                ctx.shadowBlur = 0;\n                            }\n                        }\n                    } else {\n                        // Occupied spot - draw platform\n                        ctx.fillStyle = 'rgba(58, 58, 58, 0.8)';\n                        ctx.fillRect(\n                            spot.x - SPOT_SIZE / 2,\n                            spot.y - SPOT_SIZE / 2,\n                            SPOT_SIZE,\n                            SPOT_SIZE\n                        );\n                        \n                        // Platform border\n                        ctx.strokeStyle = 'rgba(74, 144, 226, 0.3)';\n                        ctx.lineWidth = 2;\n                        ctx.strokeRect(\n                            spot.x - SPOT_SIZE / 2,\n                            spot.y - SPOT_SIZE / 2,\n                            SPOT_SIZE,\n                            SPOT_SIZE\n                        );\n                    }\n                }\n            }\n\n            function drawTurret(turret, alpha = 1) {\n                const assetId = `turret_tier${turret.tier}`;\n                const turretAsset = assets.images[assetId];\n                \n                if (turretAsset) {\n                    ctx.save();\n                    ctx.globalAlpha = alpha;\n                    \n                    ctx.drawImage(\n                        turretAsset.img,\n                        turret.x - TURRET_SIZE / 2,\n                        turret.y - TURRET_SIZE / 2,\n                        TURRET_SIZE,\n                        TURRET_SIZE\n                    );\n                    \n                    ctx.restore();\n                }\n                \n                // Range indicator when dragging\n                if (gameState.draggedTurret === turret) {\n                    const stats = TURRET_STATS[turret.tier];\n                    ctx.strokeStyle = 'rgba(74, 144, 226, 0.3)';\n                    ctx.lineWidth = 2;\n                    ctx.beginPath();\n                    ctx.arc(turret.x, turret.y, stats.range, 0, Math.PI * 2);\n                    ctx.stroke();\n                }\n            }\n\n            function drawEnemy(enemy) {\n                const assetId = `enemy_${enemy.type}`;\n                const enemyAsset = assets.images[assetId];\n                \n                if (enemyAsset) {\n                    ctx.drawImage(\n                        enemyAsset.img,\n                        enemy.x - ENEMY_SIZE / 2,\n                        enemy.y - ENEMY_SIZE / 2,\n                        ENEMY_SIZE,\n                        ENEMY_SIZE\n                    );\n                }\n                \n                // Health bar\n                const barWidth = ENEMY_SIZE;\n                const barHeight = 4;\n                const healthPercent = enemy.hp / enemy.maxHp;\n                \n                ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';\n                ctx.fillRect(\n                    enemy.x - barWidth / 2,\n                    enemy.y - ENEMY_SIZE / 2 - 8,\n                    barWidth,\n                    barHeight\n                );\n                \n                ctx.fillStyle = healthPercent > 0.5 ? '#2ecc71' : healthPercent > 0.25 ? '#f39c12' : '#e74c3c';\n                ctx.fillRect(\n                    enemy.x - barWidth / 2,\n                    enemy.y - ENEMY_SIZE / 2 - 8,\n                    barWidth * healthPercent,\n                    barHeight\n                );\n            }\n\n            function drawProjectile(projectile) {\n                ctx.fillStyle = '#00d4ff';\n                ctx.beginPath();\n                ctx.arc(projectile.x, projectile.y, 6, 0, Math.PI * 2);\n                ctx.fill();\n                \n                // Trail\n                ctx.fillStyle = 'rgba(0, 212, 255, 0.3)';\n                ctx.beginPath();\n                ctx.arc(projectile.x - projectile.vx * 0.02, projectile.y - projectile.vy * 0.02, 4, 0, Math.PI * 2);\n                ctx.fill();\n            }\n\n            function drawParticle(particle) {\n                const alpha = particle.lifetime / particle.maxLifetime;\n                \n                if (particle.type === 'muzzle_flash') {\n                    const flashAsset = assets.images['muzzle_flash'];\n                    if (flashAsset) {\n                        ctx.save();\n                        ctx.globalAlpha = alpha;\n                        ctx.drawImage(\n                            flashAsset.img,\n                            particle.x - 16,\n                            particle.y - 16,\n                            32,\n                            32\n                        );\n                        ctx.restore();\n                    }\n                } else if (particle.type === 'explosion_particle') {\n                    const expAsset = assets.images['explosion_particle'];\n                    if (expAsset) {\n                        ctx.save();\n                        ctx.globalAlpha = alpha;\n                        ctx.translate(particle.x, particle.y);\n                        ctx.rotate(particle.rotation);\n                        ctx.drawImage(\n                            expAsset.img,\n                            -12,\n                            -12,\n                            24,\n                            24\n                        );\n                        ctx.restore();\n                    }\n                } else if (particle.type === 'currency_coin') {\n                    const coinAsset = assets.images['currency_coin'];\n                    if (coinAsset) {\n                        ctx.save();\n                        ctx.globalAlpha = alpha;\n                        ctx.drawImage(\n                            coinAsset.img,\n                            particle.x - 16,\n                            particle.y - 16,\n                            32,\n                            32\n                        );\n                        ctx.restore();\n                    }\n                }\n            }\n\n            function drawLaserEffect() {\n                if (gameState.laserActive && gameState.laserTimer > 0) {\n                    const alpha = gameState.laserTimer / 0.2;\n                    \n                    // Draw laser beam from top center to target\n                    ctx.save();\n                    ctx.globalAlpha = alpha * 0.8;\n                    \n                    // Main laser beam\n                    ctx.strokeStyle = '#00d4ff';\n                    ctx.lineWidth = 8;\n                    ctx.lineCap = 'round';\n                    ctx.beginPath();\n                    ctx.moveTo(360, 0);\n                    ctx.lineTo(gameState.laserTargetX, gameState.laserTargetY);\n                    ctx.stroke();\n                    \n                    // Glow effect\n                    ctx.strokeStyle = 'rgba(0, 212, 255, 0.4)';\n                    ctx.lineWidth = 16;\n                    ctx.beginPath();\n                    ctx.moveTo(360, 0);\n                    ctx.lineTo(gameState.laserTargetX, gameState.laserTargetY);\n                    ctx.stroke();\n                    \n                    ctx.restore();\n                }\n            }\n\n            // Game loop\n            let lastTime = 0;\n            \n            function gameLoop(timestamp) {\n                const deltaTime = Math.min((timestamp - lastTime) / 1000, 0.11);\n                lastTime = timestamp;\n                \n                // Clear canvas\n                ctx.clearRect(0, 0, canvas.width, canvas.height);\n                \n                // Draw background\n                const bgGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);\n                bgGradient.addColorStop(0, '#3d2f1f');\n                bgGradient.addColorStop(1, '#2a2520');\n                ctx.fillStyle = bgGradient;\n                ctx.fillRect(0, 0, canvas.width, canvas.height);\n                \n                // Draw game elements\n                drawPath();\n                drawBase();\n                drawPlacementSpots();\n                \n                if (gameState.mode === 'play') {\n                    // Update touch hold timer\n                    if (mouseDown && gameState.hoveredSpot && !gameState.draggedTurret) {\n                        touchHoldTimer += deltaTime;\n                    }\n                    \n                    // Update game logic\n                    if (gameState.playing) {\n                        // Wave spawning\n                        const waveConfig = getWaveConfig(gameState.wave);\n                        \n                        if (gameState.waveEnemiesSpawned < gameState.waveEnemiesTotal) {\n                            gameState.waveSpawnTimer += deltaTime;\n                            \n                            if (gameState.waveSpawnTimer >= waveConfig.spawnInterval) {\n                                gameState.waveSpawnTimer = 0;\n                                \n                                // Determine enemy type\n                                const basicRemaining = waveConfig.basicCount - \n                                    gameState.enemies.filter(e => e.type === 'basic').length;\n                                const fastRemaining = waveConfig.fastCount - \n                                    gameState.enemies.filter(e => e.type === 'fast').length;\n                                \n                                let spawnType = 'basic';\n                                if (fastRemaining > 0 && (basicRemaining === 0 || Math.random() < 0.5)) {\n                                    spawnType = 'fast';\n                                }\n                                \n                                if ((spawnType === 'basic' && basicRemaining > 0) || \n                                    (spawnType === 'fast' && fastRemaining > 0)) {\n                                    spawnEnemy(spawnType);\n                                    gameState.waveEnemiesSpawned++;\n                                }\n                            }\n                        }\n                        \n                        // Update enemies\n                        for (let i = gameState.enemies.length - 1; i >= 0; i--) {\n                            const enemy = gameState.enemies[i];\n                            const reachedEnd = updateEnemyPosition(enemy, deltaTime);\n                            \n                            if (reachedEnd) {\n                                gameState.baseHealth--;\n                                gameState.enemies.splice(i, 1);\n                                \n                                if (gameState.baseHealth <= 0) {\n                                    showGameOver();\n                                }\n                            }\n                        }\n                        \n                        // Update turrets\n                        for (const spot of gameState.placementSpots) {\n                            if (spot.turret && spot.turret !== gameState.draggedTurret) {\n                                const turret = spot.turret;\n                                const stats = TURRET_STATS[turret.tier];\n                                \n                                turret.fireTimer += deltaTime;\n                                \n                                if (turret.fireTimer >= stats.fireRate) {\n                                    const target = findTarget(turret);\n                                    \n                                    if (target) {\n                                        fireProjectile(turret, target);\n                                        turret.fireTimer = 0;\n                                    }\n                                }\n                            }\n                        }\n                        \n                        // Update projectiles\n                        for (let i = gameState.projectiles.length - 1; i >= 0; i--) {\n                            const proj = gameState.projectiles[i];\n                            \n                            proj.x += proj.vx * deltaTime;\n                            proj.y += proj.vy * deltaTime;\n                            \n                            // Check collision with enemies\n                            let hit = false;\n                            for (let j = gameState.enemies.length - 1; j >= 0; j--) {\n                                const enemy = gameState.enemies[j];\n                                const dx = proj.x - enemy.x;\n                                const dy = proj.y - enemy.y;\n                                const dist = Math.sqrt(dx * dx + dy * dy);\n                                \n                                if (dist < ENEMY_SIZE / 2) {\n                                    if (damageEnemy(enemy, proj.damage)) {\n                                        gameState.enemies.splice(j, 1);\n                                    }\n                                    hit = true;\n                                    break;\n                                }\n                            }\n                            \n                            if (hit || proj.x < 0 || proj.x > canvas.width || \n                                proj.y < 0 || proj.y > canvas.height) {\n                                gameState.projectiles.splice(i, 1);\n                            }\n                        }\n                        \n                        // Update particles\n                        for (let i = gameState.particles.length - 1; i >= 0; i--) {\n                            const particle = gameState.particles[i];\n                            \n                            particle.lifetime -= deltaTime;\n                            particle.x += particle.vx * deltaTime;\n                            particle.y += particle.vy * deltaTime;\n                            \n                            if (particle.lifetime <= 0) {\n                                gameState.particles.splice(i, 1);\n                            }\n                        }\n\n                        // Update laser effect\n                        if (gameState.laserActive) {\n                            gameState.laserTimer -= deltaTime;\n                            if (gameState.laserTimer <= 0) {\n                                gameState.laserActive = false;\n                            }\n                        }\n                        \n                        // Check wave complete\n                        if (gameState.waveEnemiesSpawned >= gameState.waveEnemiesTotal && \n                            gameState.enemies.length === 0 && !gameState.waveComplete) {\n                            gameState.waveComplete = true;\n                            \n                            if (gameState.wave < 15) {\n                                playSound('wave_complete_sfx', 0.6);\n                                \n                                setTimeout(() => {\n                                    gameState.wave++;\n                                    startWave();\n                                }, 2000);\n                            } else {\n                                // Victory!\n                                showGameOver();\n                            }\n                        }\n                    }\n                    \n                    // Draw enemies\n                    for (const enemy of gameState.enemies) {\n                        drawEnemy(enemy);\n                    }\n                    \n                    // Draw projectiles\n                    for (const proj of gameState.projectiles) {\n                        drawProjectile(proj);\n                    }\n                    \n                    // Draw particles\n                    for (const particle of gameState.particles) {\n                        drawParticle(particle);\n                    }\n\n                    // Draw laser effect\n                    drawLaserEffect();\n                    \n                    // Draw turrets\n                    for (const spot of gameState.placementSpots) {\n                        if (spot.turret && spot.turret !== gameState.draggedTurret) {\n                            drawTurret(spot.turret);\n                        }\n                    }\n                    \n                    // Draw dragged turret\n                    if (gameState.draggedTurret) {\n                        const draggedTurret = { ...gameState.draggedTurret };\n                        draggedTurret.x = mousePos.x;\n                        draggedTurret.y = mousePos.y;\n                        drawTurret(draggedTurret, 0.7);\n                        \n                        // Highlight valid merge targets\n                        const targetSpot = getSpotAt(mousePos.x, mousePos.y);\n                        if (targetSpot && targetSpot !== gameState.dragStartSpot && targetSpot.turret) {\n                            if (canMergeTurrets(gameState.draggedTurret, targetSpot.turret)) {\n                                ctx.strokeStyle = 'rgba(46, 204, 113, 0.8)';\n                                ctx.lineWidth = 4;\n                                ctx.strokeRect(\n                                    targetSpot.x - SPOT_SIZE / 2,\n                                    targetSpot.y - SPOT_SIZE / 2,\n                                    SPOT_SIZE,\n                                    SPOT_SIZE\n                                );\n                            }\n                        }\n                    }\n                    \n                    updateUI();\n                }\n                \n                requestAnimationFrame(gameLoop);\n            }\n\n            // Show game parameters\n            lib.showGameParameters({\n                name: 'Game Settings',\n                params: {\n                    'Starting Currency': {\n                        key: 'startingCurrency',\n                        type: 'slider',\n                        min: 100,\n                        max: 300,\n                        step: 10\n                    },\n                    'Base Health': {\n                        key: 'baseHealth',\n                        type: 'slider',\n                        min: 10,\n                        max: 30,\n                        step: 1,\n                        onChange: (value) => {\n                            window.gameConfig.baseHealth = value;\n                            gameState.maxBaseHealth = value;\n                            if (gameState.baseHealth > value) {\n                                gameState.baseHealth = value;\n                            }\n                        }\n                    },\n                    'Spawn Rate': {\n                        key: 'spawnRateMultiplier',\n                        type: 'slider',\n                        min: 0.5,\n                        max: 2,\n                        step: 0.1\n                    },\n                    'Currency Gain': {\n                        key: 'currencyMultiplier',\n                        type: 'slider',\n                        min: 0.5,\n                        max: 2,\n                        step: 0.1\n                    },\n                    'Placement Spots': {\n                        key: 'placementSpotCount',\n                        type: 'slider',\n                        min: 8,\n                        max: 12,\n                        step: 2,\n                        onChange: (value) => {\n                            window.gameConfig.placementSpotCount = value;\n                            gameState.placementSpots = calculatePlacementSpots(value);\n                        }\n                    }\n                }\n            });\n\n            // Start game\n            if (mode === 'play') {\n                playBackgroundMusic();\n                startWave();\n            }\n            \n            requestAnimationFrame(gameLoop);\n        }\n    </script>\n</body>\n</html>", "game_config": "{\"startingCurrency\":300,\"baseHealth\":20,\"spawnRateMultiplier\":1,\"currencyMultiplier\":1,\"placementSpotCount\":10}", "game_design_document": "## Core Game Loop and Mechanics\n\n**Moment-to-Moment Gameplay:**\nPlayers experience a continuous cycle of strategic decision-making as enemy waves approach their base. The core loop consists of:\n\n1. **Enemy waves spawn** and move along a predefined path toward the player's base\n2. **Turrets automatically fire** at enemies within range, dealing damage\n3. **Defeated enemies drop currency** that players collect\n4. **Players spend currency** to place new turrets on designated spots\n5. **Identical turrets can be merged** by dragging one onto another, creating a higher-tier turret with increased damage and range\n6. **Wave difficulty increases** with faster, tougher enemies requiring better defenses\n\n**Progression System:**\n- Players start with access to basic turrets (Tier 1)\n- Merging two Tier 1 turrets creates a Tier 2 turret (better stats, different visual)\n- Merging two Tier 2 turrets creates a Tier 3 turret, and so on (up to Tier 5)\n- Each tier has significantly improved damage, range, and fire rate\n- Currency earned increases with each wave, allowing faster expansion\n\n**Win/Lose Conditions:**\n- **Lose Condition:** Enemies reach the base and deplete all health (base has 20 HP, each enemy that reaches deals 1 damage)\n- **Win Condition:** Survive as many waves as possible (endless mode with high score tracking)\n- After losing, players see their final wave number and can restart\n\n**Engagement Drivers:**\n- Satisfying merge mechanics with visual/audio feedback\n- Strategic placement decisions (coverage vs. concentrated firepower)\n- Escalating difficulty that requires constant adaptation\n- Visual spectacle of turrets firing and enemies exploding\n- High score chase encourages replayability\n\n## Starting Scope\n\n**First Iteration Must Include:**\n1. **Single linear path** from spawn point to base (simple curved path)\n2. **Three turret tiers** (Tier 1, 2, 3) with clear visual progression\n3. **Two enemy types:** Basic (slow, low HP) and Fast (quick, medium HP)\n4. **10 turret placement spots** arranged along the path\n5. **Wave system** with 15 waves, gradually introducing faster/tougher enemies\n6. **Basic UI:** Currency display, wave counter, health bar, restart button\n7. **Merge mechanic:** Drag-and-drop to combine identical turrets\n8. **Auto-firing turrets** with projectile visuals\n9. **Simple particle effects** for explosions and hits\n10. **Victory/defeat screen** with wave count\n\n**Future Iterations Can Add:**\n- Additional turret tiers (4-5)\n- More enemy types (armored, flying, boss enemies)\n- Special abilities or power-ups\n- Multiple path layouts\n- Turret selling/repositioning\n- Upgrade trees beyond merging\n- Different game modes (timed survival, limited resources)\n\n## Game Perspective\n\n**Fixed-screen with scrollable battlefield**\n\nThe game uses a **top-down perspective** with a fixed camera showing the battlefield. The path curves through the visible area from top to bottom, with the player's base at the bottom of the screen. Turret placement spots are clearly marked along the sides of the path.\n\nThe viewport is 720\u00d71280 (portrait), and the battlefield fits within this space without requiring scrolling. All action remains visible at once, allowing players to monitor the entire defense line simultaneously.\n\n## Game World and Level Design\n\n**Battlefield Layout:**\n- **Dimensions:** 720\u00d71100 playable area (leaving 180px at top for UI)\n- **Path:** A winding road that enters from the top-center, curves through the middle (creating strategic choke points), and exits at the bottom-center where the base sits\n- **Path width:** 120px, allowing enemies to move in a single file with slight randomization\n- **Base location:** Bottom-center (640px from top), represented as a fortified structure\n\n**Turret Placement Grid:**\n- **10 designated spots** arranged along both sides of the path\n- **Spots are 100\u00d7100px** with clear visual indicators (platforms/foundations)\n- **5 spots on the left side** of the path, **5 on the right side**\n- Spots positioned at strategic intervals: some near spawn (early damage), some at curves (maximum exposure time), some near base (last defense)\n- Empty spots show a subtle outline; occupied spots display the turret\n\n**Visual Theme:**\n- Post-apocalyptic wasteland with cracked earth and debris\n- Dark, desaturated background (browns, grays) to make colorful turrets and enemies pop\n- Path is a damaged road with cracks and worn paint\n- Base has defensive walls, sandbags, and warning lights\n\n**Enemy Spawn and Movement:**\n- Enemies spawn off-screen at the top and follow the path exactly\n- Movement speed varies by enemy type\n- Slight horizontal randomization (\u00b110px) prevents perfect stacking\n- Enemies that reach the base disappear and deal damage\n\n## Edit Mode Design\n\nEdit mode allows players to customize the visual theme and difficulty parameters without breaking core gameplay.\n\n**Editable Properties:**\n\n1. **Visual Customization:**\n   - **Background color scheme:** Choose from 5 presets (Wasteland, Desert, Snow, Jungle, Volcanic)\n   - **Turret color themes:** Adjust primary color for all turrets (affects tier 1-3 consistently)\n   - **Enemy color themes:** Change enemy appearance colors\n   - **Path style:** Select from 3 path textures (Cracked Road, Dirt Trail, Metal Plates)\n\n2. **Difficulty Parameters:**\n   - **Starting currency:** 100-300 (default: 150)\n   - **Base health:** 10-30 HP (default: 20)\n   - **Enemy spawn rate:** 0.5x - 2x speed multiplier (default: 1x)\n   - **Currency gain multiplier:** 0.5x - 2x (default: 1x)\n\n3. **Turret Placement:**\n   - **Number of placement spots:** 8-12 spots (default: 10)\n   - Spots automatically distribute along the path when count changes\n\n**Edit Mode UI:**\n- Accessed via an \"Edit\" button in the main menu\n- Shows the battlefield in a paused state with sample enemies frozen on path\n- Sliders and color pickers for each property\n- \"Reset to Default\" button\n- \"Save & Play\" button to apply changes\n\n**Constraints:**\n- Turret tier progression (damage/range ratios) remains fixed to maintain balance\n- Path shape and base location cannot be changed (ensures consistent strategy)\n- Minimum 8 placement spots to ensure game remains playable\n- Currency and health limits prevent trivializing or making impossible\n\n## Control Design\n\n**Desktop Controls (Mouse):**\n- **Left Click on empty spot:** Purchase and place a Tier 1 turret (if enough currency)\n- **Left Click + Drag on turret:** Pick up turret to merge with another\n- **Drop turret on identical tier:** Merge into next tier (both turrets consumed)\n- **Drop turret on empty spot:** Move turret to new location\n- **Drop turret on different tier:** Cancel action, return to original spot\n- **Hover over turret:** Show stats tooltip (tier, damage, range)\n- **Click UI buttons:** Restart, Edit Mode, etc.\n\n**Mobile Controls (Touch):**\n- **Tap empty spot:** Purchase and place Tier 1 turret (if enough currency)\n- **Tap + Hold turret (300ms):** Pick up turret (visual feedback: turret lifts and follows finger)\n- **Drag to another turret:** Merge if same tier\n- **Drag to empty spot:** Move turret\n- **Release anywhere else:** Cancel, return to original position\n- **Tap turret briefly:** Show stats popup (tier, damage, range) with close button\n- **Tap UI buttons:** Standard touch interaction\n\n**Visual Feedback:**\n- Cursor changes to \"pointer\" over interactive elements\n- Turrets highlight on hover/touch\n- Valid merge targets glow green when dragging compatible turret\n- Invalid targets show red outline\n- Insufficient currency shows red flash on empty spots\n- Smooth drag animation with turret following cursor/finger\n\n**Input Handling:**\n- Track mouse/touch state to distinguish clicks from drags\n- Prevent accidental merges with 50px minimum drag distance\n- Clear all input states on window blur\n- Disable interactions during wave transition animations\n\n## Art Style and Visual Theme\n\n**Overall Style: Stylized Post-Apocalyptic**\n\nA balance between serious apocalyptic themes and approachable, colorful game elements. The environment is dark and gritty, but turrets and effects are vibrant and satisfying.\n\n**Color Palette:**\n- **Background/Environment:** Desaturated earth tones (dark browns #3d2f1f, grays #4a4a4a, muted greens #3a4a3a)\n- **Path:** Darker asphalt gray (#2a2a2a) with lighter cracks (#5a5a5a)\n- **Turrets:** Bright, saturated colors that stand out\n  - Tier 1: Steel blue (#4a90e2) with orange accents (#ff8c42)\n  - Tier 2: Purple (#9b59b6) with yellow accents (#f1c40f)\n  - Tier 3: Red (#e74c3c) with cyan accents (#00d4ff)\n- **Enemies:** \n  - Basic: Dull red (#c0392b) with dark outlines\n  - Fast: Bright yellow (#f39c12) with dark outlines\n- **UI:** Clean, modern interface with semi-transparent dark panels (#1a1a1a at 85% opacity)\n\n**Asset Sizes and Scale:**\n- **Turrets:** 80\u00d780px (fit within 100\u00d7100px spots with padding)\n- **Enemies:** 40\u00d740px (small enough to show multiple on path)\n- **Projectiles:** 12\u00d712px (visible but not cluttering)\n- **Base:** 200\u00d7150px (prominent at bottom of screen)\n- **UI elements:** 60\u00d760px minimum for touch targets\n\n**Rendering Approach:**\n- **Code-rendered (CSS/Canvas):**\n  - Background (solid color or gradient)\n  - Path (drawn with canvas or CSS)\n  - Turret placement spots (simple outlined squares)\n  - UI panels and buttons (CSS with border-radius)\n  - Health bars (CSS rectangles)\n  - Projectiles (simple circles or small shapes)\n  \n- **Generated Assets:**\n  - Turret designs (3 tiers, each with distinct appearance)\n  - Enemy sprites (2 types)\n  - Base structure\n  - Explosion/hit particle effects\n  - Background texture/pattern (optional overlay)\n\n**Visual Consistency:**\n- All turrets share similar geometric base (cylindrical or angular platform) with different weapon designs\n- Enemies use consistent art style (top-down vehicle or creature silhouettes)\n- Viewing angle: **Top-down at 90 degrees** for all game elements\n- Lighting: Subtle top-down lighting with slight shadows beneath objects\n\n**Animation and Effects:**\n- Turret firing: Muzzle flash, recoil animation\n- Projectile travel: Smooth linear motion with slight glow trail\n- Enemy hit: Brief red flash, small particle burst\n- Enemy death: Larger explosion with 5-8 particles radiating outward\n- Merge: Bright flash, particles swirling into new turret\n- Currency collection: Coins/resources float upward and toward UI counter", "persistent_storage_config": null, "game_metadata": {"game_id": "01KQDN9WRVV2BTR2A4SCVSXTAH", "title": "Turret Defend Apocalypse", "description": "Build, merge, and upgrade turrets to defend your base from endless enemy waves in this strategic defense game!", "thumbnail_url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/thumbnail_e23956f8-4d0c-45c5-a979-37a60d974314.webp", "created_at": 1777501279.0, "updated_at": 1777548818311.5583, "art_style": null}}