{"asset_map": {"flower_rose": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_rose_5522c8b9-e400-47ec-b5c5-7ca7582a2bbc.webp", "type": "image", "prompt": "Generate a top-down view of a fully bloomed red rose. Clean, polished, slightly stylized game-ready asset. Spiral petal pattern, vibrant red with subtle shading, professional quality illustration on a transparent background. Centered, filling the frame for a square tile.", "description": "Red rose icon for memory match tile", "subtype": "object", "aspect_ratio": [896, 916], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "flower_sunflower": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_sunflower_80f6377e-5e8e-41d6-a571-10a0d22dac5d.webp", "type": "image", "prompt": "Generate a top-down view of a cheerful yellow sunflower. Match the clean, stylized art style of flower_rose. Bright yellow petals, dark brown center with seed detail, subtle shading, professional quality illustration on a transparent background. Centered, filling the frame for a square tile.", "description": "Yellow sunflower icon for memory match tile", "subtype": "object", "aspect_ratio": [989, 977], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "flower_tulip": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_tulip_4755d9d9-4197-4aa7-8a8d-5b78f78cf4b2.webp", "type": "image", "prompt": "Generate a slightly angled cup-shaped pink tulip flower. Match the clean, stylized art style of flower_rose. Soft pink petals, elegant curves, subtle shading, professional quality illustration on a transparent background. Centered, filling the frame for a square tile.", "description": "Pink tulip icon for memory match tile", "subtype": "object", "aspect_ratio": [674, 767], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "flower_daisy": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_daisy_e898b671-ccdb-42bc-9852-bb823878497f.webp", "type": "image", "prompt": "Generate a top-down view of a fresh white daisy. Match the clean, stylized art style of flower_rose. White petals radiating from a bright yellow center, subtle shading, professional quality illustration on a transparent background. Centered, filling the frame for a square tile.", "description": "White daisy icon for memory match tile", "subtype": "object", "aspect_ratio": [834, 817], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "flower_lavender": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_lavender_8fc084a9-d663-42e4-ab80-e1819eab69f3.webp", "type": "image", "prompt": "Generate a clustered purple lavender flower spike at a slight angle. Match the clean, stylized art style of flower_rose. Small clustered purple florets along a stem, soft purple tones, subtle shading, professional quality illustration on a transparent background. Centered, filling the frame for a square tile.", "description": "Purple lavender icon for memory match tile", "subtype": "object", "aspect_ratio": [411, 864], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "flower_cherry_blossom": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_cherry_blossom_f6604a11-9a54-4f78-9079-64f474281248.webp", "type": "image", "prompt": "Generate a top-down view of a delicate pink cherry blossom. Match the clean, stylized art style of flower_rose. Five soft pink petals with a small yellow center, light and airy appearance, professional quality illustration on a transparent background. Centered, filling the frame for a square tile.", "description": "Pink cherry blossom icon for memory match tile", "subtype": "object", "aspect_ratio": [741, 702], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "tile_back_pattern": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/tile_back_pattern_34314d5c-ba80-4247-b41b-a8681a2e9a8f.webp", "type": "image", "prompt": "Generate a seamless horizontally and vertically tiling texture for a game tile back. Elegant garden motif with subtle leaf and vine silhouettes. Soft green tones on a light green background, symmetrical and delicate design, professional aesthetic, no visible seams, garden-themed game asset.", "description": "Seamless floral pattern for the back of the game tiles", "subtype": "ground", "aspect_ratio": [1536, 1024], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "match_sound": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/match_sound_024b21db-9bc0-4c1e-9a1b-56a0c11c6650.mp3", "type": "audio", "prompt": "A pleasant, high-pitched magical chime with a soft sparkle effect. The sound should have a gentle, organic texture like a small crystal bell being struck, followed by a subtle floral shimmer. Short, positive, and rewarding feedback for a casual puzzle game. Clean and bright, 0.8 seconds duration.", "description": "A satisfying, cheerful chime for successfully matching two flower tiles.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.21, "loop": false, "animation": null}, "flip_sound": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/flip_sound_c6215cc8-d47e-4416-9a09-2a1c21c9c778.mp3", "type": "audio", "prompt": "A very short, soft paper or card flip sound with a gentle air whoosh. High-frequency, clean, and snappy but quiet. It should feel smooth and light, resembling a high-quality playing card being turned over on a felt surface. Non-metallic, non-intrusive.", "description": "A quick, subtle sound effect for flipping a tile card.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 0.93, "loop": false, "animation": null}, "victory_sound": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/victory_sound_50b0f7f4-0038-4cfc-b3d3-7c2dd4cac2b4.mp3", "type": "audio", "prompt": "A celebratory 3-second musical flourish. Ascending major-key bells and glockenspiel melody with a hint of magical fairy dust and soft woodwind trills. It should evoke a sense of a garden blooming at once. Joyful, triumphant, and rewarding with a clean shimmering decay tail.", "description": "A triumphant and joyful garden-themed fanfare for winning the game.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 2.34, "loop": false, "animation": null}, "background_music": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/background_music_e03769f1-e067-491c-9969-51c5fc143c46.mp3", "type": "audio", "prompt": "A calm, relaxing acoustic track for a casual garden puzzle game. Features a gentle solo piano melody accompanied by soft nylon-string guitar and very light, pizzicato strings. Peaceful, airy, and tranquil atmosphere. Medium-slow tempo, 80 BPM, in a major key. No heavy percussion or vocals. Seamless loop, high-quality production, evoking a sunny afternoon in a quiet garden.", "description": "Tranquil and relaxing acoustic background music for the floral puzzle gameplay.", "subtype": "music", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 30, "loop": true, "animation": null}, "flower_hibiscus": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_hibiscus_96e1dba9-f1b2-4327-a17b-69313e52b81c.webp", "type": "image", "prompt": "Generate a vibrant red hibiscus flower icon for a memory match game. Full-body, top-down view, centered illustration. Cartoon style with clean lines and flat shading, consistent with the style of image 1 and image 2. High resolution, professional game asset, transparent background.", "description": "A vibrant red hibiscus flower icon for a memory match tile", "subtype": "ui", "aspect_ratio": [930, 910], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "flower_lotus": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_lotus_ed2c88d4-89b4-4cf2-9d82-46646694ecfb.webp", "type": "image", "prompt": "Generate a serene pink lotus flower icon for a memory match game. Top-down view, centered composition, clean lines, polished cartoon style with vibrant colors. Ensure the asset is game-ready with a transparent background. Match the artistic style, line weight, and shading of image 1 and image 2.", "description": "A serene pink lotus flower icon for a memory match tile", "subtype": "ui", "aspect_ratio": [994, 973], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "flower_orchid": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_orchid_f85e2399-6e7c-40c5-8175-51ee741b3577.webp", "type": "image", "prompt": "Generate a high-quality, elegant purple orchid flower icon for a memory match game. Use a clean cartoon style with bold outlines and vibrant colors. Top-down view, front-facing, centered composition. The design should be simple and recognizable, matching the style of existing flower assets like image 1 and image 2. Transparent background, professional game asset.", "description": "An elegant purple orchid flower icon for a memory match tile", "subtype": "ui", "aspect_ratio": [985, 932], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "flower_poppy": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/flower_poppy_70cc4175-dda9-4f7b-ae82-ddab94766137.webp", "type": "image", "prompt": "Generate a bright orange poppy flower icon for a memory match game. Style: clean cartoon vector art, thick clean lines, vibrant colors, top-down view. The asset should be centered with a transparent background. Maintain visual consistency with the existing flower icons including the rose and sunflower.", "description": "Bright orange poppy icon for a memory match tile", "subtype": "object", "aspect_ratio": [963, 950], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}}, "game_code": "<!DOCTYPE html>\n<html>\n<head>\n    <title>Tile Match Flowers</title>\n    <link href=\"https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600&family=Poppins:wght@400;600&display=swap\" rel=\"stylesheet\">\n    <style>\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        body, html {\n            margin: 0;\n            padding: 0;\n            width: 100%;\n            height: 100%;\n            overflow: hidden;\n            touch-action: none;\n            -ms-touch-action: none;\n            font-family: 'Poppins', sans-serif;\n        }\n\n        #game-world {\n            position: relative;\n            width: 100%;\n            height: 100%;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n        }\n\n        /* Main Menu Styles */\n        .menu-container {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            width: 100%;\n            height: 100%;\n            padding: var(--space-lg);\n            box-sizing: border-box;\n        }\n\n        .game-title {\n            font-family: 'Fredoka', cursive;\n            font-size: 56px;\n            font-weight: 600;\n            color: #FFFFFF;\n            text-align: center;\n            margin-bottom: var(--space-xl);\n            text-shadow: 2px 2px 4px rgba(0,0,0,0.5);\n        }\n\n        .difficulty-buttons {\n            display: flex;\n            flex-direction: column;\n            gap: var(--space-md);\n            width: 100%;\n            max-width: 400px;\n        }\n\n        .difficulty-btn {\n            padding: var(--space-lg);\n            font-size: 32px;\n            font-weight: 600;\n            border: none;\n            border-radius: 16px;\n            cursor: pointer;\n            transition: transform var(--transition-fast) var(--ease-out),\n                        box-shadow var(--transition-fast) var(--ease-out);\n            box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n            min-height: 96px;\n        }\n\n        .difficulty-btn:active {\n            transform: scale(0.95);\n            box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n        }\n\n        .easy-btn {\n            background: linear-gradient(135deg, #A8E6CF 0%, #7FB069 100%);\n            color: white;\n        }\n\n        .hard-btn {\n            background: linear-gradient(135deg, #FFB6C1 0%, #FF8FAB 100%);\n            color: white;\n        }\n\n        /* Game Board Styles */\n        .game-container {\n            display: flex;\n            flex-direction: column;\n            width: 100%;\n            height: 100%;\n            padding: var(--space-sm);\n            box-sizing: border-box;\n        }\n\n        .game-header {\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            padding: var(--space-sm) var(--space-sm) 0 var(--space-sm);\n            margin-bottom: var(--space-sm);\n        }\n\n        .menu-btn {\n            position: fixed;\n            bottom: var(--space-md);\n            left: var(--space-md);\n            padding: var(--space-md);\n            font-size: 24px;\n            font-weight: 600;\n            background: #7FB069;\n            color: white;\n            border: none;\n            border-radius: 50%;\n            cursor: pointer;\n            box-shadow: 0 4px 16px rgba(0,0,0,0.25);\n            min-height: 96px;\n            min-width: 96px;\n            z-index: 100;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            transition: transform var(--transition-fast) var(--ease-out),\n                        box-shadow var(--transition-fast) var(--ease-out);\n        }\n\n        .menu-btn:active {\n            transform: scale(0.9);\n            box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n        }\n\n        .move-counter {\n            font-size: 28px;\n            font-weight: 600;\n            color: #FFFFFF;\n            text-align: center;\n            background: rgba(255, 255, 255, 0.2);\n            padding: var(--space-xs) var(--space-md);\n            border-radius: 20px;\n            box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n            display: flex;\n            align-items: center;\n            gap: 10px;\n        }\n\n        .lives-container {\n            display: flex;\n            gap: 5px;\n            flex-wrap: wrap;\n            justify-content: center;\n            max-width: 250px;\n        }\n\n        .heart {\n            font-size: 24px;\n            filter: drop-shadow(0 2px 2px rgba(0,0,0,0.1));\n            transition: transform 0.4s var(--ease-bounce), opacity 0.4s ease;\n        }\n\n        .heart.lost {\n            opacity: 0.2;\n            transform: scale(0.7) grayscale(1);\n        }\n\n        .board-container {\n            flex: 1;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            padding: var(--space-sm);\n        }\n\n        .tile-grid {\n            display: grid;\n            gap: 8px;\n            perspective: 1000px;\n        }\n\n        .tile {\n            position: relative;\n            cursor: pointer;\n            transform-style: preserve-3d;\n            transition: transform 0.4s var(--ease-out);\n        }\n\n        .tile.flipped {\n            transform: rotateY(180deg);\n        }\n\n        .tile.matched {\n            opacity: 0;\n            transform: rotateY(180deg) scale(0) rotate(360deg);\n            transition: opacity 0.5s var(--ease-out), \n                        transform 0.5s var(--ease-out);\n        }\n\n        .tile-face {\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            backface-visibility: hidden;\n            border-radius: 12px;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n        }\n\n        .tile-back {\n            background: #7FB069;\n            border: 3px solid white;\n        }\n\n        .tile-front {\n            transform: rotateY(180deg);\n            background: white;\n            border: 3px solid white;\n        }\n\n        .tile-front img {\n            max-width: 85%;\n            max-height: 85%;\n            object-fit: contain;\n        }\n\n        .tile-back-img {\n            max-width: 70%;\n            max-height: 70%;\n            object-fit: contain;\n            opacity: 0.4;\n        }\n\n        /* Victory and Game Over Styles */\n        .victory-container, .game-over-container {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            width: 100%;\n            height: 100%;\n            padding: var(--space-lg);\n            box-sizing: border-box;\n            position: relative;\n        }\n\n        .victory-title, .game-over-title {\n            font-family: 'Fredoka', cursive;\n            font-size: 52px;\n            font-weight: 600;\n            color: #FFFFFF;\n            text-align: center;\n            margin-bottom: var(--space-md);\n            animation: bounceIn 0.6s var(--ease-bounce);\n        }\n\n        .game-over-title {\n            color: #A03030;\n        }\n\n        .victory-stats, .game-over-stats {\n            font-size: 32px;\n            color: #CCCCCC;\n            margin-bottom: var(--space-xl);\n            text-align: center;\n        }\n\n        .victory-buttons, .game-over-buttons {\n            display: flex;\n            flex-direction: column;\n            gap: var(--space-md);\n            width: 100%;\n            max-width: 400px;\n        }\n\n        .victory-btn, .game-over-btn {\n            padding: var(--space-lg);\n            font-size: 28px;\n            font-weight: 600;\n            border: none;\n            border-radius: 16px;\n            cursor: pointer;\n            box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n            min-height: 96px;\n            color: white;\n        }\n\n        .play-again-btn {\n            background: linear-gradient(135deg, #FFD93D 0%, #FFA500 100%);\n            font-size: 32px;\n            min-height: 110px;\n        }\n\n        .try-again-btn {\n            background: linear-gradient(135deg, #FFB6C1 0%, #FF6B6B 100%);\n            font-size: 32px;\n            min-height: 110px;\n        }\n\n        .menu-victory-btn {\n            background: linear-gradient(135deg, #A8E6CF 0%, #7FB069 100%);\n            font-size: 24px;\n            min-height: 80px;\n            opacity: 0.9;\n        }\n\n        /* Animations */\n        @keyframes bounceIn {\n            0% {\n                opacity: 0;\n                transform: scale(0.3);\n            }\n            50% {\n                opacity: 1;\n                transform: scale(1.05);\n            }\n            70% {\n                transform: scale(0.9);\n            }\n            100% {\n                transform: scale(1);\n            }\n        }\n\n        .confetti {\n            position: absolute;\n            width: 10px;\n            height: 10px;\n            border-radius: 50%;\n            animation: confettiFall 3s linear infinite;\n        }\n\n        @keyframes confettiFall {\n            0% {\n                transform: translateY(-100px) rotate(0deg);\n                opacity: 1;\n            }\n            100% {\n                transform: translateY(1400px) rotate(720deg);\n                opacity: 0;\n            }\n        }\n\n        .match-text {\n            position: absolute;\n            top: 180px;\n            left: 50%;\n            transform: translateX(-50%);\n            font-size: 56px;\n            font-family: 'Fredoka', cursive;\n            font-weight: 600;\n            color: #FFD93D;\n            text-shadow: 0 4px 12px rgba(0,0,0,0.5);\n            z-index: 1000;\n            pointer-events: none;\n            animation: matchFadeUp 1.5s ease-out forwards;\n        }\n\n        @keyframes matchFadeUp {\n            0% { opacity: 0; transform: translate(-50%, 20px); }\n            20% { opacity: 1; transform: translate(-50%, 0); }\n            80% { opacity: 1; transform: translate(-50%, -20px); }\n            100% { opacity: 0; transform: translate(-50%, -40px); }\n        }\n    </style>\n</head>\n<body>\n    <div id=\"game-world\"></div>\n\n    <script>\n        /**\n         * Tile Match Flowers - A Memory Matching Game\n         * \n         * A beautiful floral-themed memory game where players flip tiles to find matching\n         * pairs of flowers. Features easy and hard difficulty modes, smooth animations,\n         * and a calming garden aesthetic.\n         * \n         * Core Mechanics:\n         * - Flip tiles to reveal flowers underneath\n         * - Match pairs of identical flowers\n         * - Matched pairs spin and disappear\n         * - Mismatched pairs flip back after a delay\n         * - Track moves and celebrate victory\n         */\n\n        async function run(mode) {\n            const gameWorld = document.getElementById('game-world');\n            \n            // Game state\n            const state = {\n                screen: 'MENU', // MENU, PLAYING, VICTORY, GAMEOVER\n                difficulty: null,\n                tiles: [],\n                flippedTiles: [],\n                matchedPairs: 0,\n                totalPairs: 0,\n                moves: 0,\n                lives: 0,\n                canFlip: true,\n                audioContext: null,\n                audioBuffers: {}\n            };\n\n            // Asset cache\n            const assets = {\n                flowers: {},\n                tileBack: null,\n                sounds: {}\n            };\n\n            const flowerNames = {\n                'flower_rose': 'Rose',\n                'flower_sunflower': 'Sunflower',\n                'flower_tulip': 'Tulip',\n                'flower_daisy': 'Daisy',\n                'flower_lavender': 'Lavender',\n                'flower_cherry_blossom': 'Cherry Blossom',\n                'flower_hibiscus': 'Hibiscus',\n                'flower_lotus': 'Lotus',\n                'flower_orchid': 'Orchid',\n                'flower_poppy': 'Poppy'\n            };\n\n            // Initialize audio context\n            function initAudio() {\n                if (!state.audioContext) {\n                    state.audioContext = new (window.AudioContext || window.webkitAudioContext)();\n                }\n            }\n\n            // Preload assets\n            async function preloadAssets() {\n                const assetIds = [\n                    'flower_rose', 'flower_sunflower', 'flower_tulip',\n                    'flower_daisy', 'flower_lavender', 'flower_cherry_blossom',\n                    'flower_hibiscus', 'flower_lotus', 'flower_orchid', 'flower_poppy',\n                    'tile_back_pattern', 'match_sound', 'flip_sound',\n                    'victory_sound', 'background_music'\n                ];\n\n                const loadPromises = assetIds.map(id => {\n                    return new Promise((resolve) => {\n                        const assetInfo = lib.getAsset(id);\n                        if (!assetInfo) {\n                            resolve();\n                            return;\n                        }\n\n                        if (assetInfo.type === 'image') {\n                            const img = new Image();\n                            img.onload = () => {\n                                if (id === 'tile_back_pattern') {\n                                    assets.tileBack = img;\n                                } else {\n                                    assets.flowers[id] = img;\n                                }\n                                resolve();\n                            };\n                            img.onerror = () => resolve();\n                            img.src = assetInfo.url;\n                        } else if (assetInfo.type === 'audio') {\n                            fetch(assetInfo.url)\n                                .then(response => response.arrayBuffer())\n                                .then(arrayBuffer => {\n                                    if (!state.audioContext) initAudio();\n                                    return state.audioContext.decodeAudioData(arrayBuffer);\n                                })\n                                .then(audioBuffer => {\n                                    state.audioBuffers[id] = audioBuffer;\n                                    resolve();\n                                })\n                                .catch(() => resolve());\n                        }\n                    });\n                });\n\n                await Promise.all(loadPromises);\n            }\n\n            // Play sound\n            function playSound(soundId) {\n                if (!state.audioContext || !state.audioBuffers[soundId]) return;\n                \n                const source = state.audioContext.createBufferSource();\n                source.buffer = state.audioBuffers[soundId];\n                source.connect(state.audioContext.destination);\n                source.start(0);\n            }\n\n            await preloadAssets();\n\n            // Show game parameters\n            lib.showGameParameters({\n                name: 'Tile Match Flowers',\n                params: {\n                    'Tile Back Color': {\n                        key: 'tileBackColor',\n                        type: 'color'\n                    },\n                    'Tile Border Color': {\n                        key: 'tileBorderColor',\n                        type: 'color'\n                    },\n                    'Tile Border Width': {\n                        key: 'tileBorderWidth',\n                        type: 'slider',\n                        min: 1,\n                        max: 5,\n                        step: 1\n                    },\n                    'Background Color': {\n                        key: 'backgroundColor',\n                        type: 'color'\n                    },\n                    'Board Spacing': {\n                        key: 'boardSpacing',\n                        type: 'slider',\n                        min: 4,\n                        max: 20,\n                        step: 2\n                    },\n                    'Easy Grid Rows': {\n                        key: 'easyGridRows',\n                        type: 'slider',\n                        min: 3,\n                        max: 5,\n                        step: 1\n                    },\n                    'Easy Grid Columns': {\n                        key: 'easyGridCols',\n                        type: 'slider',\n                        min: 3,\n                        max: 5,\n                        step: 1\n                    },\n                    'Hard Grid Rows': {\n                        key: 'hardGridRows',\n                        type: 'slider',\n                        min: 4,\n                        max: 7,\n                        step: 1\n                    },\n                    'Hard Grid Columns': {\n                        key: 'hardGridCols',\n                        type: 'slider',\n                        min: 4,\n                        max: 5,\n                        step: 1\n                    },\n                    'Flip Duration (ms)': {\n                        key: 'flipDuration',\n                        type: 'slider',\n                        min: 200,\n                        max: 600,\n                        step: 50\n                    },\n                    'Match Delay (ms)': {\n                        key: 'matchDelay',\n                        type: 'slider',\n                        min: 300,\n                        max: 1000,\n                        step: 100\n                    },\n                    'Mismatch Delay (ms)': {\n                        key: 'mismatchDelay',\n                        type: 'slider',\n                        min: 800,\n                        max: 2000,\n                        step: 100\n                    },\n                    'Starting Lives': {\n                        key: 'startingLives',\n                        type: 'slider',\n                        min: 1,\n                        max: 5,\n                        step: 1\n                    }\n                }\n            });\n\n            // Apply background color\n            function updateBackground() {\n                gameWorld.style.backgroundColor = window.gameConfig.backgroundColor;\n            }\n            updateBackground();\n\n            // Create main menu\n            function showMenu() {\n                state.screen = 'MENU';\n                gameWorld.innerHTML = `\n                    <div class=\"menu-container\">\n                        <div class=\"game-title\">\ud83c\udf38 Tile Match Flowers \ud83c\udf38</div>\n                        <div class=\"difficulty-buttons\">\n                            <button class=\"difficulty-btn easy-btn\" id=\"easy-btn\">Easy</button>\n                            <button class=\"difficulty-btn hard-btn\" id=\"hard-btn\">Hard</button>\n                        </div>\n                    </div>\n                `;\n\n                document.getElementById('easy-btn').addEventListener('click', () => startGame('easy'));\n                document.getElementById('hard-btn').addEventListener('click', () => startGame('hard'));\n            }\n\n            // Start game with selected difficulty\n            function startGame(difficulty) {\n                state.difficulty = difficulty;\n                state.moves = 0;\n                state.lives = window.gameConfig.startingLives || 2;\n                state.matchedPairs = 0;\n                state.flippedTiles = [];\n                state.canFlip = true;\n                state.screen = 'PLAYING';\n\n                // Get grid dimensions\n                const rows = difficulty === 'easy' ? window.gameConfig.easyGridRows : window.gameConfig.hardGridRows;\n                const cols = difficulty === 'easy' ? window.gameConfig.easyGridCols : window.gameConfig.hardGridCols;\n                const totalTiles = rows * cols;\n                state.totalPairs = totalTiles / 2;\n\n                // Generate tile pairs\n                const flowerTypes = [\n                    'flower_rose', 'flower_sunflower', 'flower_tulip', \n                    'flower_daisy', 'flower_lavender', 'flower_cherry_blossom',\n                    'flower_hibiscus', 'flower_lotus', 'flower_orchid', 'flower_poppy'\n                ];\n                \n                // Shuffle flower types so different ones appear each game\n                for (let i = flowerTypes.length - 1; i > 0; i--) {\n                    const j = Math.floor(Math.random() * (i + 1));\n                    [flowerTypes[i], flowerTypes[j]] = [flowerTypes[j], flowerTypes[i]];\n                }\n\n                const tiles = [];\n                for (let i = 0; i < state.totalPairs; i++) {\n                    const flowerType = flowerTypes[i % flowerTypes.length];\n                    tiles.push({ flower: flowerType, matched: false });\n                    tiles.push({ flower: flowerType, matched: false });\n                }\n\n                // Shuffle tiles\n                for (let i = tiles.length - 1; i > 0; i--) {\n                    const j = Math.floor(Math.random() * (i + 1));\n                    [tiles[i], tiles[j]] = [tiles[j], tiles[i]];\n                }\n\n                state.tiles = tiles;\n                renderGame();\n            }\n\n            // Render game board\n            function renderGame() {\n                const rows = state.difficulty === 'easy' ? window.gameConfig.easyGridRows : window.gameConfig.hardGridRows;\n                const cols = state.difficulty === 'easy' ? window.gameConfig.easyGridCols : window.gameConfig.hardGridCols;\n                \n                // Calculate tile size\n                const containerWidth = 720 - 32; // Account for padding\n                const containerHeight = 1280 - 140; // Account for header and padding\n                const spacing = window.gameConfig.boardSpacing;\n                \n                const tileWidth = Math.floor((containerWidth - (cols - 1) * spacing) / cols);\n                const tileHeight = Math.floor((containerHeight - (rows - 1) * spacing) / rows);\n                const tileSize = Math.min(tileWidth, tileHeight);\n\n                gameWorld.innerHTML = `\n                    <div class=\"game-container\">\n                        <div class=\"game-header\">\n                            <div class=\"move-counter\">\n                                <span>Moves: <span id=\"move-count\">${state.moves}</span></span>\n                                <div class=\"lives-container\" id=\"lives-container\"></div>\n                            </div>\n                        </div>\n                        <div class=\"board-container\">\n                            <div class=\"tile-grid\" id=\"tile-grid\" style=\"grid-template-columns: repeat(${cols}, ${tileSize}px); gap: ${spacing}px;\"></div>\n                        </div>\n                        <button class=\"menu-btn\" id=\"menu-btn\">\u2261</button>\n                    </div>\n                `;\n\n                updateLivesUI();\n\n                const grid = document.getElementById('tile-grid');\n                state.tiles.forEach((tile, index) => {\n                    const tileDiv = document.createElement('div');\n                    tileDiv.className = 'tile';\n                    tileDiv.style.width = `${tileSize}px`;\n                    tileDiv.style.height = `${tileSize}px`;\n                    tileDiv.dataset.index = index;\n\n                    const backFace = document.createElement('div');\n                    backFace.className = 'tile-face tile-back';\n                    backFace.style.backgroundColor = window.gameConfig.tileBackColor;\n                    backFace.style.border = `${window.gameConfig.tileBorderWidth}px solid ${window.gameConfig.tileBorderColor}`;\n                    \n                    if (assets.tileBack) {\n                        const backImg = document.createElement('img');\n                        backImg.src = assets.tileBack.src;\n                        backImg.className = 'tile-back-img';\n                        backFace.appendChild(backImg);\n                    }\n\n                    const frontFace = document.createElement('div');\n                    frontFace.className = 'tile-face tile-front';\n                    frontFace.style.border = `${window.gameConfig.tileBorderWidth}px solid ${window.gameConfig.tileBorderColor}`;\n                    \n                    if (assets.flowers[tile.flower]) {\n                        const flowerImg = document.createElement('img');\n                        flowerImg.src = assets.flowers[tile.flower].src;\n                        frontFace.appendChild(flowerImg);\n                    }\n\n                    tileDiv.appendChild(backFace);\n                    tileDiv.appendChild(frontFace);\n                    grid.appendChild(tileDiv);\n\n                    if (mode === 'play') {\n                        tileDiv.addEventListener('click', () => handleTileClick(index));\n                    }\n                });\n\n                document.getElementById('menu-btn').addEventListener('click', showMenu);\n            }\n\n            // Handle tile click\n            function handleTileClick(index) {\n                if (!state.canFlip) return;\n                if (state.tiles[index].matched) return;\n                if (state.flippedTiles.includes(index)) return;\n                if (state.flippedTiles.length >= 2) return;\n\n                // Flip tile\n                const tileDiv = document.querySelector(`[data-index=\"${index}\"]`);\n                tileDiv.classList.add('flipped');\n                state.flippedTiles.push(index);\n                playSound('flip_sound');\n\n                if (state.flippedTiles.length === 2) {\n                    state.moves++;\n                    document.getElementById('move-count').textContent = state.moves;\n                    checkMatch();\n                }\n            }\n\n            // Update lives UI display\n            function updateLivesUI() {\n                const container = document.getElementById('lives-container');\n                if (!container) return;\n                \n                const maxLives = window.gameConfig.startingLives || 2;\n                container.innerHTML = '';\n                \n                for (let i = 0; i < maxLives; i++) {\n                    const heart = document.createElement('span');\n                    heart.className = 'heart' + (i >= state.lives ? ' lost' : '');\n                    heart.innerHTML = '\u2764\ufe0f';\n                    container.appendChild(heart);\n                }\n            }\n\n            // Check if flipped tiles match\n            function checkMatch() {\n                state.canFlip = false;\n                const [index1, index2] = state.flippedTiles;\n                const tile1 = state.tiles[index1];\n                const tile2 = state.tiles[index2];\n\n                if (tile1.flower === tile2.flower) {\n                    // Match found\n                    playSound('match_sound');\n\n                    // Show flower name\n                    const flowerName = flowerNames[tile1.flower] || 'Match!';\n                    const matchText = document.createElement('div');\n                    matchText.className = 'match-text';\n                    matchText.textContent = flowerName;\n                    gameWorld.appendChild(matchText);\n                    setTimeout(() => matchText.remove(), 1500);\n                    \n                    // Gain a life back if match was successful (cap at starting lives)\n                    const maxLives = window.gameConfig.startingLives || 2;\n                    if (state.lives < maxLives) {\n                        state.lives++;\n                        updateLivesUI();\n                    }\n\n                    setTimeout(() => {\n                        tile1.matched = true;\n                        tile2.matched = true;\n                        \n                        const tileDiv1 = document.querySelector(`[data-index=\"${index1}\"]`);\n                        const tileDiv2 = document.querySelector(`[data-index=\"${index2}\"]`);\n                        \n                        if (tileDiv1) tileDiv1.classList.add('matched');\n                        if (tileDiv2) tileDiv2.classList.add('matched');\n                        \n                        state.matchedPairs++;\n                        state.flippedTiles = [];\n                        state.canFlip = true;\n\n                        if (state.matchedPairs === state.totalPairs) {\n                            setTimeout(() => showVictory(), 600);\n                        }\n                    }, window.gameConfig.matchDelay);\n                } else {\n                    // No match\n                    state.lives--;\n                    updateLivesUI();\n\n                    setTimeout(() => {\n                        const tileDiv1 = document.querySelector(`[data-index=\"${index1}\"]`);\n                        const tileDiv2 = document.querySelector(`[data-index=\"${index2}\"]`);\n                        \n                        if (tileDiv1) tileDiv1.classList.remove('flipped');\n                        if (tileDiv2) tileDiv2.classList.remove('flipped');\n                        \n                        state.flippedTiles = [];\n                        \n                        if (state.lives <= 0) {\n                            setTimeout(() => showGameOver(), 500);\n                        } else {\n                            state.canFlip = true;\n                        }\n                    }, window.gameConfig.mismatchDelay);\n                }\n            }\n\n            // Show game over screen\n            function showGameOver() {\n                state.screen = 'GAMEOVER';\n                \n                gameWorld.innerHTML = `\n                    <div class=\"game-over-container\">\n                        <div class=\"game-over-title\">\ud83d\udc94 Try Again! \ud83d\udc94</div>\n                        <div class=\"game-over-stats\">Out of lives! You matched ${state.matchedPairs} pairs.</div>\n                        <div class=\"victory-buttons\">\n                            <button class=\"victory-btn try-again-btn\" id=\"try-again-btn\">Try Again</button>\n                            <button class=\"victory-btn menu-victory-btn\" id=\"menu-victory-btn\">Main Menu</button>\n                        </div>\n                    </div>\n                `;\n\n                document.getElementById('try-again-btn').addEventListener('click', () => startGame(state.difficulty));\n                document.getElementById('menu-victory-btn').addEventListener('click', showMenu);\n            }\n\n            // Show victory screen\n            function showVictory() {\n                state.screen = 'VICTORY';\n                playSound('victory_sound');\n                \n                gameWorld.innerHTML = `\n                    <div class=\"victory-container\">\n                        <div class=\"victory-title\">\ud83c\udf89 Garden Complete! \ud83c\udf89</div>\n                        <div class=\"victory-stats\">Completed in ${state.moves} moves!</div>\n                        <div class=\"victory-buttons\">\n                            <button class=\"victory-btn play-again-btn\" id=\"play-again-btn\">Play Again</button>\n                            <button class=\"victory-btn menu-victory-btn\" id=\"menu-victory-btn\">Main Menu</button>\n                        </div>\n                    </div>\n                `;\n\n                // Add confetti\n                for (let i = 0; i < 50; i++) {\n                    setTimeout(() => {\n                        const container = document.querySelector('.victory-container');\n                        if (!container) return; // Exit if victory screen is no longer active\n\n                        const confetti = document.createElement('div');\n                        confetti.className = 'confetti';\n                        confetti.style.left = `${Math.random() * 100}%`;\n                        confetti.style.top = '-50px';\n                        confetti.style.backgroundColor = ['#FFB6C1', '#FFD93D', '#A8E6CF', '#DDA0DD', '#87CEEB'][Math.floor(Math.random() * 5)];\n                        confetti.style.animationDelay = `${Math.random() * 2}s`;\n                        container.appendChild(confetti);\n                        \n                        setTimeout(() => {\n                            if (confetti.parentNode) confetti.remove();\n                        }, 3000);\n                    }, i * 50);\n                }\n\n                document.getElementById('play-again-btn').addEventListener('click', () => startGame(state.difficulty));\n                document.getElementById('menu-victory-btn').addEventListener('click', showMenu);\n            }\n\n            if (mode === 'edit') {\n                // Edit mode: Show menu with visual feedback\n                showMenu();\n                \n                // Watch for config changes and update visuals\n                const originalConfig = JSON.stringify(window.gameConfig);\n                setInterval(() => {\n                    const currentConfig = JSON.stringify(window.gameConfig);\n                    if (currentConfig !== originalConfig) {\n                        updateBackground();\n                        if (state.screen === 'PLAYING') {\n                            renderGame();\n                        }\n                    }\n                }, 500);\n            } else {\n                // Play mode: Start with menu\n                showMenu();\n            }\n        }\n    </script>\n</body>\n</html>", "game_config": "{\n  \"tileBackColor\": \"#7FB069\",\n  \"tileBackPattern\": \"floral\",\n  \"tileBorderColor\": \"#FFFFFF\",\n  \"tileBorderWidth\": 3,\n  \"backgroundColor\": \"#000000\",\n  \"boardSpacing\": 8,\n  \"easyGridRows\": 4,\n  \"easyGridCols\": 4,\n  \"hardGridRows\": 6,\n  \"hardGridCols\": 4,\n  \"flipDuration\": 400,\n  \"matchDelay\": 500,\n  \"mismatchDelay\": 1200,\n  \"startingLives\": 10\n}", "game_design_document": "## Core Game Loop and Mechanics\n\n**Tile Match Flowers** is a classic memory matching game with a beautiful floral theme. The core gameplay loop consists of:\n\n1. **Game Start**: Player selects difficulty (Easy or Hard) from a main menu\n2. **Tile Flipping**: Player taps/clicks on face-down tiles to reveal the flower hidden underneath\n3. **Matching Logic**: \n   - When a tile is flipped, it stays face-up\n   - Player flips a second tile\n   - If the two flowers match: both tiles spin and fade out with a satisfying animation, remaining cleared\n   - If they don't match: both tiles flip back face-down after a brief delay (~1 second)\n4. **Progression**: Player continues flipping tiles until all pairs are matched\n5. **Victory**: When all pairs are found, show a victory screen with confetti/celebration and option to play again or change difficulty\n\n**Win Condition**: Match all flower pairs on the board\n\n**Engagement Drivers**:\n- Satisfying flip and match animations\n- Challenge of remembering tile positions\n- Quick, replayable rounds\n- Beautiful floral visuals that are calming and appealing\n\n## Starting Scope\n\nFor the first iteration, implement:\n- Main menu with difficulty selection (Easy/Hard buttons)\n- Complete gameplay with tile flipping and matching logic\n- Victory screen with replay option\n- Beautiful floral theme with 6 different flower types\n- Smooth animations for tile flips, matches, and disappearances\n- Move counter to track player performance\n\n**Leave for future iterations**:\n- Timer/time-based scoring\n- High score tracking\n- Additional difficulty levels\n- Sound effects toggle\n- More flower varieties\n- Hint system\n\n## Game Perspective\n\n**Fixed-screen, top-down view**: The game uses a single screen with a grid of tiles viewed from directly above. No scrolling is needed - the entire game board fits within the 720\u00d71280 viewport.\n\n## Game World and Level Design\n\n**Main Menu Screen**:\n- Game title at top with decorative flower elements\n- Two large, thumb-friendly buttons in center:\n  - \"Easy\" button (4\u00d74 grid = 16 tiles, 8 pairs)\n  - \"Hard\" button (4\u00d76 grid = 24 tiles, 12 pairs)\n- Soft, garden-themed background\n\n**Game Board Layout**:\n- **Easy Mode**: 4 columns \u00d7 4 rows = 16 tiles (8 matching pairs)\n- **Hard Mode**: 4 columns \u00d7 6 rows = 24 tiles (12 matching pairs)\n- Tiles arranged in a centered grid with comfortable spacing\n- Each tile is square with rounded corners\n- Tiles have a decorative back design (floral pattern or garden motif)\n- Board positioned in upper-middle portion of screen\n- Move counter displayed at top\n- Small \"Menu\" button in top-left corner to return to difficulty selection\n\n**Victory Screen**:\n- Celebratory message (\"Perfect Match!\" or \"Garden Complete!\")\n- Display number of moves taken\n- Confetti or flower petal animation\n- Two buttons: \"Play Again\" (same difficulty) and \"Menu\" (return to difficulty selection)\n\n## Edit Mode Design\n\nPlayers can customize the following in Edit mode:\n\n**Tile Appearance**:\n- `tileBackColor`: Color of the tile back (default: soft green)\n- `tileBackPattern`: Pattern style for tile backs (\"floral\", \"solid\", \"gradient\")\n- `tileBorderColor`: Border color for tiles (default: white)\n- `tileBorderWidth`: Border thickness in pixels (1-5, default: 3)\n\n**Board Settings**:\n- `backgroundColor`: Game background color (default: light cream/beige)\n- `boardSpacing`: Gap between tiles in pixels (4-20, default: 8)\n\n**Difficulty Settings**:\n- `easyGridRows`: Number of rows for easy mode (3-5, default: 4)\n- `easyGridCols`: Number of columns for easy mode (3-5, default: 4)\n- `hardGridRows`: Number of rows for hard mode (4-7, default: 6)\n- `hardGridCols`: Number of columns for hard mode (4-5, default: 4)\n\n**Animation Settings**:\n- `flipDuration`: Tile flip animation speed in ms (200-600, default: 400)\n- `matchDelay`: Delay before matched tiles disappear in ms (300-1000, default: 500)\n- `mismatchDelay`: Delay before mismatched tiles flip back in ms (800-2000, default: 1200)\n\n**Constraints**:\n- Grid dimensions must result in an even number of tiles (for pairing)\n- Minimum 12 tiles, maximum 30 tiles total\n- Tile sizes automatically adjust to fit the screen based on grid size\n\n## Control Design\n\n**Mobile (Touch)**:\n- **Tap tile**: Flip tile to reveal flower\n- **Tap Menu button**: Return to main menu\n- **Tap difficulty button**: Start game with selected difficulty\n- **Tap Play Again/Menu on victory screen**: Navigate accordingly\n\n**Desktop (Mouse + Keyboard)**:\n- **Click tile**: Flip tile to reveal flower\n- **Click buttons**: Navigate menus\n- **Escape key**: Return to main menu (when in game)\n- **Enter key**: Confirm selection on menus\n\n**Input Handling**:\n- Prevent flipping more than 2 tiles at once\n- Disable tile interaction during flip animations and mismatch delay\n- Prevent flipping already-matched tiles\n- Prevent flipping the same tile twice in a row\n\n## Art Style and Visual Theme\n\n**Overall Style**: Soft, cheerful, and garden-inspired with a modern casual game aesthetic\n\n**Color Palette**:\n- Background: Soft cream, light beige, or pale green\n- Tile backs: Gentle green with subtle floral pattern\n- Tile borders: Clean white or light gold\n- Flowers: Vibrant but not oversaturated colors (roses, sunflowers, tulips, daisies, lavender, cherry blossoms)\n\n**Visual Elements**:\n- **Tiles**: Rounded square cards with subtle shadow for depth\n- **Flowers**: Illustrated in a clean, slightly stylized manner (not photorealistic, not overly cartoony)\n- **Animations**: Smooth 3D flip effect for tiles, gentle spin + fade for matched pairs\n- **UI Elements**: Rounded buttons with soft shadows, clear readable text\n- **Decorative Elements**: Small flower or leaf accents around the title and borders\n\n**Asset Approach**:\n- Generate flower images as individual assets\n- Use CSS/Canvas for tile backgrounds, borders, and UI elements\n- Implement flip animation with CSS 3D transforms\n- Create particle effects for victory celebration with Canvas", "persistent_storage_config": null, "game_metadata": {"game_id": "01KSA5P17X6694F77MQ2NWAQAM", "title": "Tile Match Flowers", "description": "**Description:** Flip colorful flower tiles to find matching pairs in this relaxing memory puzzle game with easy and hard difficulty modes!", "thumbnail_url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/thumbnail_bbcf63c0-d76d-4360-bbe5-ec3ae85cd362.webp", "created_at": 1779532590, "updated_at": 1779729011389.9226, "art_style": null}}