{"asset_map": {"player_character": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/31ed7b0a-c28c-4e75-ac9d-e709479cfc8d.webp?scale=25", "type": "image", "prompt": "Minecraft-style character, top-down view, full body standing illustration, chunky voxel style, blue shirt and brown pants, blocky pixelated design, transparent background, game-ready asset", "description": "Minecraft-style player character for top-down view", "subtype": "character", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "tree_type_1": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/3f3a04cf-6301-4996-803d-47e2635ef153.webp?scale=50", "type": "image", "prompt": "Minecraft-style tree, top-down view, chunky voxel design, brown blocky trunk with green pixelated leaves, simple geometric shapes, transparent background, game-ready asset", "description": "First tree variant in chunky voxel style", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "tree_type_2": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/8163a8ba-3e1b-4f12-b69e-0dbaa791aceb.webp?scale=50", "type": "image", "prompt": "Minecraft-style tree, top-down view, chunky voxel design, darker brown blocky trunk with darker green pixelated leaves, different leaf pattern from first tree, transparent background, game-ready asset", "description": "Second tree variant in chunky voxel style", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "tree_type_3": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/e670d5af-bdb5-456b-86cf-61e77e3561d9.webp?scale=50", "type": "image", "prompt": "Minecraft-style tree, top-down view, chunky voxel design, lighter brown blocky trunk with bright green pixelated leaves, unique leaf arrangement, transparent background, game-ready asset", "description": "Third tree variant in chunky voxel style", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "grass_texture": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/a43ccd80-6890-474a-863f-066849bf2839.webp?scale=50&quality=90", "type": "image", "prompt": "Seamless tileable grass texture, top-down view, natural green grass pattern, chunky pixelated style matching Minecraft aesthetic, high resolution, detailed, professional quality", "description": "Seamless grass texture for infinite background tiling", "subtype": "ground", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "firewood_pile": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/736437ef-d6d0-4509-b0be-be033236bb28.webp?scale=25", "type": "image", "prompt": "Minecraft-style pile of firewood logs, top-down view, chunky voxel design, brown pixelated wooden logs stacked in a small pile, blocky geometric shapes, simple textures, transparent background, game-ready asset", "description": "Minecraft-style pile of firewood logs, top-down view, chunky voxel design, brown pixelated wooden logs stacked in a small pile, blocky geometric shapes, simple textures, transparent background, game-ready asset", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "minecraft_axe": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/085fb518-7b11-40ab-9384-98c92da55692.webp?scale=25", "type": "image", "prompt": "Minecraft-style axe, 3D voxel style, chunky blocky design, wooden handle with brown pixelated texture, metal axe head with gray/silver blocky surface, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading", "description": "Minecraft-style axe, 3D voxel style, chunky blocky design, wooden handle with brown pixelated texture, metal axe head with gray/silver blocky surface, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "green_wood_particle": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/cf9f6009-7db4-4511-8672-427f1e7fa613.webp?scale=4", "type": "image", "prompt": "Minecraft-style green wood particle, small voxel cube texture, bright green color like minecraft leaves, chunky pixelated design, 3D cube appearance with visible faces and edges, blocky geometric shape, transparent background", "description": "Minecraft-style green wood particle, small voxel cube texture, bright green color like minecraft leaves, chunky pixelated design, 3D cube appearance with visible faces and edges, blocky geometric shape, transparent background", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "brown_wood_particle": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/b267030a-bd12-4a8b-a1f3-991a80dd5a1b.webp?scale=4", "type": "image", "prompt": "Minecraft-style brown wood particle, small voxel cube texture, brown color like minecraft wood logs, chunky pixelated design, 3D cube appearance with visible faces and edges, blocky geometric shape, transparent background", "description": "Minecraft-style brown wood particle, small voxel cube texture, brown color like minecraft wood logs, chunky pixelated design, 3D cube appearance with visible faces and edges, blocky geometric shape, transparent background", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "minecraft_rock": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/c88c8b7e-ae08-468b-bc6b-399ba9aafbb4.webp?scale=12", "type": "image", "prompt": "Minecraft-style grey rock, isometric 3D voxel style, chunky blocky design, grey stone texture with darker grey shading, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated surface details, simple blocky form, transparent background, game-ready asset", "description": "Minecraft-style grey rock, isometric 3D voxel style, chunky blocky design, grey stone texture with darker grey shading, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated surface details, simple blocky form, transparent background, game-ready asset", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "minecraft_flower": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/42f8dadd-84a9-4830-9421-2674f85f896d.webp?scale=12", "type": "image", "prompt": "Minecraft-style flower plant, isometric 3D voxel style, chunky blocky design, bright colorful flower petals (red, yellow, or pink), green blocky stem and leaves, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated plant texture, simple blocky botanical form, transparent background, game-ready asset", "description": "Minecraft-style flower plant, isometric 3D voxel style, chunky blocky design, bright colorful flower petals (red, yellow, or pink), green blocky stem and leaves, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated plant texture, simple blocky botanical form, transparent background, game-ready asset", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "grey_particle": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/3cbcf652-8c6f-4e81-962f-82b00a426e92.webp?scale=4", "type": "image", "prompt": "Minecraft-style grey stone particle, small voxel cube texture, grey color like minecraft cobblestone, chunky pixelated design, 3D cube appearance with visible faces and edges, blocky geometric shape, simple grey stone texture, transparent background", "description": "Minecraft-style grey stone particle, small voxel cube texture, grey color like minecraft cobblestone, chunky pixelated design, 3D cube appearance with visible faces and edges, blocky geometric shape, simple grey stone texture, transparent background", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "red_particle": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/df8be41c-2cc9-4e0e-aa4e-40594497c6dd.webp?scale=4", "type": "image", "prompt": "Minecraft-style red particle, small voxel cube texture, bright red color like minecraft redstone or red flowers, chunky pixelated design, 3D cube appearance with visible faces and edges, blocky geometric shape, transparent background", "description": "Minecraft-style red particle, small voxel cube texture, bright red color like minecraft redstone or red flowers, chunky pixelated design, 3D cube appearance with visible faces and edges, blocky geometric shape, transparent background", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "minecraft_wolf": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/1068d2b7-988b-45ec-9a48-f27b8200a3f7.webp?scale=25", "type": "image", "prompt": "Minecraft-style grey wolf with red eyes, 3D voxel style, chunky blocky design, grey fur with darker grey shading, bright red glowing eyes, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated wolf texture, simple blocky animal form, transparent background, game-ready asset", "description": "Minecraft-style grey wolf with red eyes, 3D voxel style, chunky blocky design, grey fur with darker grey shading, bright red glowing eyes, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated wolf texture, simple blocky animal form, transparent background, game-ready asset", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "minecraft_raw_meat": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/d1f93cc2-262a-4491-adc9-21216f30798a.webp?scale=25", "type": "image", "prompt": "Minecraft-style raw meat fillet, 3D voxel style, chunky blocky design, red/pink raw meat texture with darker red marbling, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated meat texture, simple blocky food item, transparent background, game-ready asset", "description": "Minecraft-style raw meat fillet, 3D voxel style, chunky blocky design, red/pink raw meat texture with darker red marbling, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated meat texture, simple blocky food item, transparent background, game-ready asset", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "minecraft_frog": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/7da6e994-84ad-4af2-9e08-f26266cb6383.webp?scale=25", "type": "image", "prompt": "Minecraft-style frog, 3D voxel style, chunky blocky design, bright green skin with darker green spots, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated amphibian texture, simple blocky animal form with visible legs and body, transparent background, game-ready asset", "description": "Minecraft-style frog, 3D voxel style, chunky blocky design, bright green skin with darker green spots, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated amphibian texture, simple blocky animal form with visible legs and body, transparent background, game-ready asset", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "minecraft_poison_spear": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/7429fa37-107a-4f93-bd33-7f8aa4ef8442.webp?scale=25", "type": "image", "prompt": "Minecraft-style poison spear, 3D voxel style, chunky blocky design, wooden handle with brown pixelated texture, bright green spear tip with glowing green poison effect, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading", "description": "Minecraft-style poison spear, 3D voxel style, chunky blocky design, wooden handle with brown pixelated texture, bright green spear tip with glowing green poison effect, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "horror_deer": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/f761bd70-b9db-4665-823e-a8933a59636b.webp?scale=50", "type": "image", "prompt": "Horror deer creature, solid black body, walking upright on hind legs like a human, long pointy fingers on front hands/arms, large round white eyes with small black pupils in center, mouth open showing teeth, large black antlers on head, Minecraft voxel style, chunky blocky design, top-down angled view, transparent background, game-ready asset", "description": "Horror deer creature, solid black body, walking upright on hind legs like a human, long pointy fingers on front hands/arms, large round white eyes with small black pupils in center, mouth open showing teeth, large black antlers on head, Minecraft voxel style, chunky blocky design, top-down angled view, transparent background, game-ready asset", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "horror_deer_hungry": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/gpt/c122ba6a-ba00-4b4a-8534-d7231c3170cf.webp?scale=50", "type": "image", "prompt": "Horror deer creature identical to existing horror deer but with bright red glowing eyes instead of white eyes. Solid black body, walking upright on hind legs like a human, long pointy fingers on front hands/arms, mouth open showing teeth, large black antlers on head, Minecraft voxel style, chunky blocky design, top-down angled view, transparent background, game-ready asset. The eyes should be bright red and glowing, everything else exactly the same as the original deer.", "description": "Horror deer creature identical to existing horror deer but with bright red glowing eyes instead of white eyes. Solid black body, walking upright on hind legs like a human, long pointy fingers on front hands/arms, mouth open showing teeth, large black antlers on head, Minecraft voxel style, chunky blocky design, top-down angled view, transparent background, game-ready asset. The eyes should be bright red and glowing, everything else exactly the same as the original deer.", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "pink_skateboard": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/pink_skateboard_b7cde8b6-e730-4a71-8243-c931b40ae485.webp", "type": "image", "prompt": "Transform the skateboard from image 1 into a Ben 10 Omnitrix themed version. The deck should be solid black with a bright green glowing Omnitrix hourglass symbol in the center. The wheels must be neon green and glowing. The trucks and axles are dark grey metallic. Add a neon green outline glow around the board edges. Maintain the chunky cartoon aesthetic and top-down angled view. High resolution, game-ready asset on a transparent background.", "description": "A Ben 10 / Omnitrix themed skateboard with a glowing green alien logo and neon accents.", "subtype": "object", "aspect_ratio": [884, 805], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "horror_deer_demonic": {"url": "https://d3rwqceq3gv95x.cloudfront.net/assets/images/59bb6c4c-cb1e-40df-97c6-a552ddb4abc6.webp?scale=50", "type": "image", "prompt": "Horror deer creature identical to existing horror deer but with fully red body instead of black. Walking upright on hind legs like a human, long pointy fingers on front hands/arms, large round white eyes with small black pupils in center (keep eyes the same as original), mouth open showing teeth, large black antlers on head, Minecraft voxel style, chunky blocky design, top-down angled view, transparent background, game-ready asset. The entire body should be bright red color, only the antlers remain black.", "description": "Horror deer creature identical to existing horror deer but with fully red body instead of black. Walking upright on hind legs like a human, long pointy fingers on front hands/arms, large round white eyes with small black pupils in center (keep eyes the same as original), mouth open showing teeth, large black antlers on head, Minecraft voxel style, chunky blocky design, top-down angled view, transparent background, game-ready asset. The entire body should be bright red color, only the antlers remain black.", "subtype": "other", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "bed": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/efe5f752-2896-42b4-8289-3b51abdad64e.webp?scale=25", "type": "image", "prompt": "Minecraft style bed, chunky voxel blocky design, wooden frame, white linen, white pillow, salmon color eiderdown, pixelated bed texture, simple blocky bed form, transparent background, game-ready asset", "description": "Minecraft style bed, chunky voxel blocky design, wooden frame, white linen, white pillow, salmon color eiderdown, pixelated bed texture, simple blocky bed form, transparent background, game-ready asset", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "blue_skateboard": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/e61489de-18c1-4bf3-b10c-1b27bab1dee2.webp?scale=25", "type": "image", "prompt": "Blue and yellow skateboard, Minecraft voxel style, chunky blocky design, mid-blue with yellow lightning decals, top-down angled view showing the deck and wheels, pixelated skateboard texture, simple blocky skateboard form, transparent background, game-ready asset", "description": "Blue and yellow skateboard, Minecraft voxel style, chunky blocky design, mid-blue with yellow lightning decals, top-down angled view showing the deck and wheels, pixelated skateboard texture, simple blocky skateboard form, transparent background, game-ready asset", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "gold_skateboard": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/1124845a-a2d1-4c74-8df5-7e6455632708.webp?scale=25", "type": "image", "prompt": "Solid gold skateboard, Minecraft voxel style, chunky blocky design, shiny polished gold, top-down angled view showing the deck and wheels, pixelated skateboard texture, simple blocky skateboard form, transparent background, game-ready asset", "description": "Solid gold skateboard, Minecraft voxel style, chunky blocky design, shiny polished gold, top-down angled view showing the deck and wheels, pixelated skateboard texture, simple blocky skateboard form, transparent background, game-ready asset", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "yellow_axe": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/2e9abba7-9331-4f80-944b-e192b0eac187.webp?scale=25", "type": "image", "prompt": "Minecraft-style axe, 3D voxel style, chunky blocky design, bright yellow handle with pixelated texture, metal axe head with black blocky surface, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading. Vertically oriented handle. Blade head facing right", "description": "Minecraft-style axe, 3D voxel style, chunky blocky design, bright yellow handle with pixelated texture, metal axe head with black blocky surface, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading. Vertically oriented handle. Blade head facing right", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "red_axe": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/e08124a3-bf58-47c9-a3ec-a1ca605a4b99.webp?scale=25", "type": "image", "prompt": "Minecraft-style axe, 3D voxel style, chunky blocky design, bright red handle with pixelated texture, metal axe head with red blocky surface, silver metal blade, silver details, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading. Vertically oriented handle, blade head facing right", "description": "Minecraft-style axe, 3D voxel style, chunky blocky design, bright red handle with pixelated texture, metal axe head with red blocky surface, silver metal blade, silver details, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading. Vertically oriented handle, blade head facing right", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "base_spear": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/e9633af4-c681-405a-b3e4-be2e555c3a5b.webp?scale=25", "type": "image", "prompt": "Minecraft-style wooden spear, 3D voxel style, chunky blocky design, light wooden handle with light brown pixelated texture, light brown spear tip same color as handle, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading. Orientation pointing top-right", "description": "Minecraft-style wooden spear, 3D voxel style, chunky blocky design, light wooden handle with light brown pixelated texture, light brown spear tip same color as handle, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading. Orientation pointing top-right", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "metal_spear": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/aa05b134-304d-4c36-bccb-f17d678cb051.webp?scale=25", "type": "image", "prompt": "Minecraft-style wooden spear, 3D voxel style, chunky blocky design, wooden handle with brown pixelated texture, shiny silver metal spear tip with, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading. Orientation pointing top-right", "description": "Minecraft-style wooden spear, 3D voxel style, chunky blocky design, wooden handle with brown pixelated texture, shiny silver metal spear tip with, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading. Orientation pointing top-right", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "workstation": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/7ef5a4eb-3700-42b3-b1e2-ab000e67e54b.webp?scale=19", "type": "image", "prompt": "Minecraft crafting table, 3D voxel style, chunky blocky design, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading", "description": "Minecraft crafting table, 3D voxel style, chunky blocky design, top-down angled view showing depth and dimension, transparent background, game-ready asset, detailed voxel shading", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "child_1": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/6047da98-bbb1-433d-873e-fb6286a349d6.webp?scale=25", "type": "image", "prompt": "Minecraft-style girl child character, top-down view, full body standing illustration, chunky voxel style, pink shirt and light blue pants, green eyes, blonde hair, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left", "description": "Minecraft-style girl child character, top-down view, full body standing illustration, chunky voxel style, pink shirt and light blue pants, green eyes, blonde hair, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "child_2": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/371e49eb-4e7b-401c-afc3-1f7cdfd3d8fa.webp?scale=25", "type": "image", "prompt": "Minecraft-style girl child character, top-down view, full body standing illustration, chunky voxel style, white dress with small flower details, blue eyes, long red hair, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left", "description": "Minecraft-style girl child character, top-down view, full body standing illustration, chunky voxel style, white dress with small flower details, blue eyes, long red hair, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "child_3": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/beaff352-d41c-4b90-bba9-ef0735f2987b.webp?scale=25", "type": "image", "prompt": "Minecraft-style boy child character, top-down view, full body standing illustration, chunky voxel style, yellow shirt purple pants, hazel eyes, short black, tanned skin, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left", "description": "Minecraft-style boy child character, top-down view, full body standing illustration, chunky voxel style, yellow shirt purple pants, hazel eyes, short black, tanned skin, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "child_4": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/c5021afd-c481-4eb5-8da3-481661cb3eda.webp?scale=25", "type": "image", "prompt": "Minecraft-style boy child character, top-down view, full body standing illustration, chunky voxel style, black shirt, dark green pants, closed eyes that are flat black line horizontally, short black hair split down the middle, light skin, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left", "description": "Minecraft-style boy child character, top-down view, full body standing illustration, chunky voxel style, black shirt, dark green pants, closed eyes that are flat black line horizontally, short black hair split down the middle, light skin, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "bear": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/09c7eea4-f6fb-46b6-872e-2aafd82ea5cf.webp?scale=29", "type": "image", "prompt": "Minecraft-style brown bear with red eyes, 3D voxel style, chunky blocky design, brown fur with darker brown shading, bright red glowing eyes, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated bear texture, simple blocky animal form, transparent background, game-ready asset", "description": "Minecraft-style brown bear with red eyes, 3D voxel style, chunky blocky design, brown fur with darker brown shading, bright red glowing eyes, cubic geometric shapes, top-down angled view showing depth and dimension, pixelated bear texture, simple blocky animal form, transparent background, game-ready asset", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "radar": {"url": "https://d2vvvmmcuq3beq.cloudfront.net/assets/images/bb696349-a8f3-4eaa-8ef6-810a7077ddab.webp?scale=39", "type": "image", "prompt": "Minecraft-style radar tower, chunky voxel blocky design, wooden base, pixelated texture, simple blocky radar tower antennae and dish form, transparent background, game-ready asset", "description": "Minecraft-style radar tower, chunky voxel blocky design, wooden base, pixelated texture, simple blocky radar tower antennae and dish form, transparent background, game-ready asset", "subtype": "object", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null, "size_hint": null, "view": null, "outline": null, "image_asset_type": null, "audio_type": null, "edited": null, "edit_instructions": null, "edit_reason": null, "original_url": null, "error": null, "duration_hint": null}, "wardrobe": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/wardrobe_fa0f7c83-f2b7-4455-9ff4-e2ab7f783e2b.webp", "type": "image", "prompt": "Generate a futuristic alien tech locker in the Ben 10 cartoon art style, serving as a wardrobe replacement. The object should have a sleek dark metallic black body with glowing neon green panel lines and hexagonal tech patterns. Feature a prominent green glowing Omnitrix hourglass symbol centered on the front door. Top-down angled view, isometric perspective. Clean, bold cartoon outlines, vibrant green emissive lighting effects. High resolution, professional game asset, transparent background.", "description": "A Ben 10 themed futuristic alien tech locker with glowing green Omnitrix accents.", "subtype": "object", "aspect_ratio": [486, 1230], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "spongebob_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/spongebob_skin_fe631b49-4534-484b-a400-44c356dc9aa6.webp", "type": "image", "prompt": "Generate a full-body standing illustration of SpongeBob SquarePants in a Minecraft voxel style. Chunky blocky design, yellow square porous body, white eyes with black pupils, wearing a white shirt and a red tie with brown rectangular pants. Top-down view, facing left with a stiff posture. Blocky pixelated design, transparent background, game-ready asset, subtle lighting from the left, high resolution, professional quality voxel art.", "description": "SpongeBob SquarePants character in a Minecraft-style voxel aesthetic for a top-down game.", "subtype": "character", "aspect_ratio": [701, 1347], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "patrick_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/patrick_skin_b67df332-9bf8-4717-a61c-30314d761dd9.webp", "type": "image", "prompt": "Generate a full-body standing illustration of Patrick Star from SpongeBob SquarePants in a Minecraft voxel style. Chunky blocky design, pink/magenta star-shaped blocky body, lime green shorts with purple flower patterns, white blocky eyes with small black pupils. Top-down view, facing left with a stiff posture. High-quality 3D voxel art, chunky pixelated textures, clean geometric edges, subtle lighting from the left, transparent background, game-ready asset.", "description": "Patrick Star character in a Minecraft voxel style for a top-down view", "subtype": "character", "aspect_ratio": [501, 986], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "squidward_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/squidward_skin_c1d4af74-f635-47ad-8067-aec278075928.webp", "type": "image", "prompt": "Generate a Squidward Tentacles character in Minecraft voxel style, chunky blocky design, cyan/teal colored body, large blocky nose, white eyes with black pupils, wearing a brown polo shirt. Top-down view, full body standing illustration, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left, matching the style of spongebob_skin and patrick_skin.", "description": "Squidward Tentacles character skin in a Minecraft-style voxel aesthetic for top-down gameplay.", "subtype": "character", "aspect_ratio": [527, 1160], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "mr_krabs_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/mr_krabs_skin_19d65b8e-e258-4010-ae86-50d738c0abbf.webp", "type": "image", "prompt": "Mr. Krabs character from Spongebob Squarepants in Minecraft voxel style, chunky blocky 3D design, red shell body with light blue shirt and dark blue pants, large blocky claws, tall white eyes with black pupils, top-down view, full body standing illustration, blocky pixelated design, transparent background, game-ready asset. Facing left, stiff posture. Subtle lighting from left, matching the style of squidward_skin and spongebob_skin.", "description": "Mr. Krabs character skin in a Minecraft-style voxel aesthetic for a top-down perspective.", "subtype": "character", "aspect_ratio": [857, 1351], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "chocolate_cake_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/chocolate_cake_skin_32556124-d847-4d01-acd6-768ae42cb217.webp", "type": "image", "prompt": "Generate a full-body, standing illustration of an anthropomorphic chocolate cake character in a Minecraft 3D voxel style. The character has a chunky blocky design with dark brown cake layers and frosting for its body, featuring simple arms and legs. It has a cute simple face with small eyes. Top-down angled view showing depth and dimension, pixelated texture, blocky geometric shapes, transparent background, game-ready asset, high resolution, detailed voxel shading.", "description": "An anthropomorphic chocolate cake character in Minecraft voxel style for a top-down game.", "subtype": "character", "aspect_ratio": [727, 1280], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "vanilla_cake_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/vanilla_cake_skin_896e0819-f612-447f-bfdf-e7dda8dd654d.webp", "type": "image", "prompt": "Generate a Minecraft-style vanilla cake character skin, full-body standing illustration. The character is an anthropomorphized vanilla cake with blocky legs and arms, chunky 3D voxel design. Light cream and beige body resembling cake layers with thick white frosting on top, cute simple pixelated face. Top-down angled view showing depth and dimension, blocky geometric shapes, simple pixelated texture. Match the artistic style and proportions of image 1. High resolution, game-ready asset, transparent background.", "description": "A Minecraft-style anthropomorphized vanilla cake character skin for top-down gameplay.", "subtype": "character", "aspect_ratio": [708, 1246], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "strawberry_cake_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/strawberry_cake_skin_9694bd69-a762-42a1-b80e-d502541d845e.webp", "type": "image", "prompt": "Generate a Minecraft-style strawberry cake character skin, full body standing illustration, anthropomorphized with blocky arms and legs. The character features a chunky voxel design with layers of pink cake and pink frosting. Cute simple pixelated face, top-down angled view showing 3D depth and dimension. High-quality game-ready asset with a clean pixelated texture, transparent background, matching the style of chocolate_cake_skin and vanilla_cake_skin.", "description": "An anthropomorphized strawberry cake character skin in a Minecraft voxel style.", "subtype": "character", "aspect_ratio": [708, 1246], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "red_velvet_cake_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/red_velvet_cake_skin_ac761f97-c120-4bf1-902d-83690b248045.webp", "type": "image", "prompt": "Generate a Minecraft-style red velvet cake character skin, full body picture, standing illustration. The character is an anthropomorphized red velvet cake with blocky legs and arms, chunky 3D voxel design. Deep red body resembling red velvet cake layers with white cream cheese frosting, cute simple face with eyes, standing upright like a humanoid character. Top-down angled view showing depth and dimension, pixelated texture, simple blocky form, transparent background, game-ready asset. Match the style and proportions of chocolate_cake_skin and vanilla_cake_skin.", "description": "An anthropomorphized red velvet cake character skin in a Minecraft-style voxel aesthetic.", "subtype": "character", "aspect_ratio": [709, 1245], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "ben10_grass": {"url": "https://d16qq0o35va7kz.cloudfront.net/images/Google_113059840438576948815/1781648094922_01KV980XPAYH5WADE2GK69F5XP.1781646235045-019ed263-6080-7a0d-b792-888930d9c720.png", "type": "image", "prompt": null, "description": "Seamless Ben 10 alien forest floor with dark ground and glowing neon circuit patterns for game background", "subtype": null, "aspect_ratio": [941, 1672], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "ben10_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_skin_1d3b060d-ae7f-4c62-bad2-9ba71b9f23a1.webp", "type": "image", "prompt": "Generate a full-body standing illustration of Ben Tennyson from the original Ben 10 animated series. 10-year-old boy wearing his iconic white T-shirt with a thick vertical black stripe, green cargo pants, and white sneakers. The green Omnitrix device is on his left wrist and glowing. Brown hair, determined expression. Top-down angled view, facing left. Clean cartoon style matching the original series aesthetic, bold outlines, blocky cartoon design. High resolution, game-ready sprite, transparent background.", "description": "Ben Tennyson in original Ben 10 cartoon style, top-down view for game character", "subtype": "character", "aspect_ratio": [756, 1465], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "heatblast_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/heatblast_skin_b51300a1-1f03-4a04-9ae5-6c43729780cc.webp", "type": "image", "prompt": "Generate a full-body standing illustration of Heatblast from the original Ben 10 animated series, top-down view. A fiery alien creature made of a black rocky exterior with bright orange and yellow flames glowing through the cracks and covering his body. Round head with a flaming top, short stocky body. Style: chunky cartoon design matching the Ben 10 animated series aesthetic. Facing left, transparent background, high resolution, detailed, professional game-ready asset.", "description": "Heatblast character from Ben 10 in a chunky cartoon style for top-down gameplay.", "subtype": "character", "aspect_ratio": [764, 1226], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "fourarms_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/fourarms_skin_ff95d4e4-e4ba-4d04-9147-ddfc6b6d6508.webp", "type": "image", "prompt": "Generate a full-body, top-down view standing illustration of Four Arms from the original Ben 10 series. The character is a massive, muscular red-skinned alien with four arms and four eyes. He wears white pants with a black stripe. Use a chunky, clean cartoon art style consistent with Ben 10. Facing left, standing on a transparent background. High resolution, game-ready sprite with bold outlines.", "description": "Ben 10's Four Arms alien transformation in a chunky cartoon style for top-down gameplay.", "subtype": "character", "aspect_ratio": [786, 1165], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "xlr8_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/xlr8_skin_dfea7a11-483b-40cf-9e73-d5665c4ed7c3.webp", "type": "image", "prompt": "Generate a full-body standing illustration of XLR8 from the original Ben 10 animated series, top-down view. A sleek blue and black velociraptor-like alien with a black visor helmet, blue body, black details, and a white chest. Featuring his iconic wheel-like feet and aerodynamic tail. Style: Chunky cartoon design matching the Ben 10 series aesthetic, clean lines, polished game-ready asset. Facing left, transparent background, high resolution.", "description": "XLR8 character skin from Ben 10 in a chunky cartoon style for top-down gameplay", "subtype": "character", "aspect_ratio": [686, 1205], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "diamondhead_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/diamondhead_skin_e511cfdb-5206-4663-ab11-9ea85a4aa75c.webp", "type": "image", "prompt": "Generate a full-body standing illustration of Diamondhead from the original Ben 10 animated series. The character is an alien made of translucent green crystal with an angular faceted body and a sharp diamond-spike head. Top-down view, facing left. He has black and white uniform details. Cartoon Ben 10 art style, chunky and bold outlines, clean cell shading, transparent background, game-ready asset. Match the visual style of ben10_skin.", "description": "Diamondhead character from Ben 10 in a chunky cartoon style for top-down gameplay", "subtype": "character", "aspect_ratio": [562, 1211], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "ben10_tree_1": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_tree_1_48c7e6ec-f77d-4d1e-b1d2-e57c45ec7890.webp", "type": "image", "prompt": "Generate a Ben 10 cartoon style alien tree for a top-down survival game. The tree features a dark purple and dark green trunk with glowing green bioluminescent veins. The canopy consists of large, chunky alien leaves in dark teal and dark green with neon green edges. 2D stylized cartoon aesthetic with bold outlines, top-down angled view, game-ready asset, high resolution, transparent background.", "description": "An alien bioluminescent tree in the Ben 10 cartoon art style for a survival horror environment.", "subtype": "object", "aspect_ratio": [965, 952], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "ben10_tree_2": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_tree_2_7c9031eb-a8e4-4168-ae58-59a17f67ec16.webp", "type": "image", "prompt": "Generate a chunky Ben 10 cartoon style alien tree for a top-down game. Thick dark brown trunk with orange glowing cracks and veins. The canopy is wide and round, deep dark green with orange bioluminescent spots. Top-down angled view, clean cartoon lines, vibrant colors, game-ready asset, transparent background. Match the artistic style of image 1.", "description": "A chunky Ben 10 style alien tree with a dark brown trunk, orange glowing veins, and bioluminescent spots on the canopy.", "subtype": "object", "aspect_ratio": [1024, 1010], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "ben10_tree_3": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_tree_3_8cacdb13-eee5-426c-b980-386acd651698.webp", "type": "image", "prompt": "Generate a Ben 10 cartoon style alien mushroom tree for a top-down survival game. The asset should feature a giant alien mushroom shape with a thick grey-green stem and a large, wide cap that is dark purple with bright neon green polka dots that glow slightly. Use a chunky cartoon aesthetic consistent with the Ben 10 universe. Top-down angled view (isometric style), clean line art, vibrant colors, transparent background, game-ready asset, high resolution.", "description": "A Ben 10 style alien mushroom tree with a purple cap and glowing green spots for a top-down survival game.", "subtype": "object", "aspect_ratio": [899, 879], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "ben10_alien_wolf": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_alien_wolf_d4605590-5876-4a3a-a253-9a10a231ab49.webp", "type": "image", "prompt": "Generate a full-body, top-down angled view of an alien predator creature in the Ben 10 cartoon art style. The creature is a four-legged alien wolf with grey-blue scaly skin, sharp black claws, and a wide snarling mouth showing fangs. It has prominent glowing red eyes. The design should be chunky, stylized, and menacing, matching the aesthetic of image 1 and image 2. Professional game asset, clean lines, vibrant colors, transparent background.", "description": "A Ben 10 cartoon style alien wolf creature with grey-blue scales and glowing red eyes, designed for a top-down perspective.", "subtype": "character", "aspect_ratio": [964, 927], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "ben10_alien_bear": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_alien_bear_d42f4e9d-7283-4a1a-9810-d16f5d9e2faf.webp", "type": "image", "prompt": "Generate a large hulking alien beast in the original Ben 10 cartoon style, top-down angled view. The creature has thick dark purple rocky armor-like skin, four muscular arms, and glowing red eyes. Its body is massive and rounded like a boulder with powerful legs. Threatening and chunky cartoon aesthetic, clean lines, bold colors, game-ready illustration, transparent background.", "description": "A large, hulking four-armed alien beast in Ben 10 cartoon style, acting as a bear-type enemy.", "subtype": "character", "aspect_ratio": [980, 755], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "ben10_alien_frog": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_alien_frog_fe9d0753-2af1-4472-81e1-a340c7152420.webp", "type": "image", "prompt": "Generate a Ben 10 cartoon style small alien creature, top-down angled view. The creature is small and round with bright lime green slimy skin, huge bulging yellow eyes, tiny stubby legs, and a wide grin showing small sharp teeth. Designed as a game asset with a chunky cartoon aesthetic, vibrant colors, clean thick outlines, transparent background.", "description": "A small round lime-green alien creature in Ben 10 cartoon style to replace a frog.", "subtype": "character", "aspect_ratio": [813, 805], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "ben10_rock": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_rock_754afee2-e87e-4c38-9f24-fa52b92a8195.webp", "type": "image", "prompt": "Generate a Ben 10 cartoon style alien rock and crystal formation for a top-down game. The asset consists of a cluster of dark grey jagged rocks with glowing neon green crystal shards protruding from the surface, resembling alien minerals. Use a chunky, stylized cartoon aesthetic with bold outlines and vibrant colors matching the Ben 10 universe. Top-down angled view showing depth, transparent background, high resolution, game-ready asset.", "description": "A Ben 10 cartoon style alien rock with glowing green crystal shards, top-down view", "subtype": "object", "aspect_ratio": [905, 871], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "ben10_flower": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_flower_488f1beb-d715-4127-b123-194fe776dcab.webp", "type": "image", "prompt": "Generate a Ben 10 cartoon style alien plant for a top-down game. The asset is a small alien flora with a thick dark green stem and a large, glowing lime-green bioluminescent flower bulb at the top. Use a chunky, polished cartoon aesthetic with bold outlines and vibrant colors matching the Ben 10 universe. Top-down angled view, high resolution, professional game asset, transparent background.", "description": "A bioluminescent alien flower in the Ben 10 cartoon style for environmental decoration.", "subtype": "object", "aspect_ratio": [627, 987], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "sfx_axe_hit": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/sfx_axe_hit_8c601db4-e8d2-4d4c-85c2-3caf52dd0d4f.mp3", "type": "audio", "prompt": "A sharp, punchy wood chopping sound effect for a cartoon-style game. The sound features a solid 'thwack' with a heavy wood impact and a slight splintering texture. It has a quick attack, a clean resonance, and a very short decay. High-quality, non-metallic, satisfying impact sound suitable for repeated resource gathering.", "description": "Short, punchy wood chopping sound effect for an axe hitting a tree.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 0.88, "loop": false, "animation": null}, "sfx_collect": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/sfx_collect_58227687-288d-4a8c-a9b8-c0bf47b6ae57.mp3", "type": "audio", "prompt": "A bright, satisfying item collection pickup sound effect for a cartoon game. High-pitched cheerful chime with a subtle bubble pop layer. Short, snappy, and rewarding. 0.4 seconds of audio with a clean tail. Instant attack, melodic rising interval, no background noise, high quality digital synthesis.", "description": "A bright and cheerful cartoon-style chime for item collection.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.41, "loop": false, "animation": null}, "sfx_player_hurt": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/sfx_player_hurt_23c87401-37bd-4943-a901-7344af051b5f.mp3", "type": "audio", "prompt": "A sharp, punchy player hurt sound effect. A quick masculine grunt combined with a soft physical thud impact. Clear and high-quality, designed for a video game feedback cue. No background noise, non-metallic, similar in style to a classic action-adventure game. Immediate attack with a very short decay.", "description": "Short impact sound effect with a vocal grunt to indicate player damage.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.79, "loop": false, "animation": null}, "sfx_night_warning": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/sfx_night_warning_1588f7cf-03ee-4984-8db8-50c5f73b7117.mp3", "type": "audio", "prompt": "A chilling and ominous horror game warning sound. It begins with a deep, vibrating low-frequency drone that swells into a distant, ghostly wolf howl-like synthesizer tone. High-reverb, atmospheric, and haunting. The sound should evoke a sense of dread and immediate danger as darkness falls. Cinematic horror aesthetic, clean production, no background noise.", "description": "An ominous and chilling atmospheric warning cue signaling the transition to night in a horror survival setting.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.89, "loop": false, "animation": null}, "sfx_levelup": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/sfx_levelup_2220d3cc-a023-49af-8cee-f15ab3ce01a5.mp3", "type": "audio", "prompt": "A triumphant, high-quality level up sound effect for a cartoon adventure game. Features a bright, ascending melodic chime or a short brassy fanfare. The sound should be celebratory and satisfying, with a clean shimmering tail. Includes a high-pitched magical sparkle effect. No background noise, one-shot impact, 90s console game aesthetic.", "description": "Triumphant ascending level-up chime for character progression feedback", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.960249433106576, "loop": false, "animation": null}, "sfx_deer_growl": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/sfx_deer_growl_90def604-407d-4f0f-b3c0-3b37ba4c49a1.mp3", "type": "audio", "prompt": "A terrifying, otherworldly monster growl for a horror game. Starts with a deep, guttural animalistic rattle and transitions into a distorted, high-pitched screech. Unsettling and eerie textures, organic but processed to sound supernatural. Sharp attack with a lingering creepy decay. One-shot sound effect, high fidelity, 1 second long.", "description": "A terrifying, deep, and distorted animal growl for a horror deer creature.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.95, "loop": false, "animation": null}, "sfx_campfire": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/sfx_campfire_a5ab7d31-bb26-4052-8302-8dd69f9d8995.mp3", "type": "audio", "prompt": "Gentle campfire crackling and burning sound effect. Warm, cozy fire ambience with rhythmic wood snaps and soft hissing. Peaceful atmosphere, high-quality recording, no background wind or birds. Designed to be loopable without gaps or sudden jumps in volume. Suitable for a survival game crafting station or campsite.", "description": "A warm, crackling campfire ambience for a survival game atmosphere.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 5.0, "loop": true, "animation": null}, "sfx_craft": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/sounds/effect/sfx_craft_a948cd1f-0eb9-472f-9cef-8868e6e4d384.mp3", "type": "audio", "prompt": "A sharp, satisfying wood crafting sound effect for a survival game. The sound features a clean hammer-on-wood strike followed immediately by a mechanical wooden 'thunk' or locking click. It should sound solid and rewarding, conveying successful construction. Minimal reverb, dry, punchy, and designed for frequent UI/gameplay feedback in a cartoonish yet grounded style.", "description": "A satisfying wood construction sound effect featuring a hammer strike and a locking click, used for building structures.", "subtype": "effect", "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 1.38, "loop": false, "animation": null}, "ben10_axe": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_axe_9716b6de-6a68-40c8-9d11-9cd8312dfe19.webp", "type": "image", "prompt": "Generate a high-quality game asset of a classic square-headed lumberjack axe in a Ben 10 / Omnitrix tech aesthetic. The axe head is large and rectangular with a flat top edge, made of dark metallic black metal with glowing neon green energy trim along the sharp edge. The handle is short and black with green hex-tech markings. Top-down angled view showing 3D depth, the axe head faces right with the handle pointing down-left. High resolution, clean edges, professional game UI style, transparent background.", "description": "A square-headed traditional axe with a Ben 10 alien tech aesthetic and glowing green accents.", "subtype": "object", "aspect_ratio": [768, 935], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "ben10_meat": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_meat_c54c054d-b101-48b3-a02c-4430a2f2c240.webp", "type": "image", "prompt": "Generate a piece of bioluminescent alien creature flesh, purple and teal colored with faint glowing veins. Designed as a food item for a survival game. Top-down angled view, transparent background, cartoon Ben 10 art style, chunky bold outlines, vibrant colors, game-ready asset, high resolution, detailed shading.", "description": "Bioluminescent alien meat food item in a Ben 10 cartoon style", "subtype": "object", "aspect_ratio": [1018, 902], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "ben10_workstation": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_workstation_e7cd480d-dc53-4511-863c-9bf0bbfa1633.webp", "type": "image", "prompt": "Generate a futuristic alien tech workbench for a Ben 10 themed game. The workstation has a black metallic body with vibrant green energy lines and glowing green Omnitrix symbols on the top surface. Include small holographic display elements floating above the table. Top-down angled view (isometric), clean cartoon Ben 10 art style, bold chunky outlines, game-ready asset, transparent background, high resolution.", "description": "An Omnitrix-themed futuristic alien crafting workbench with holographic displays.", "subtype": "object", "aspect_ratio": [792, 879], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "ben10_campfire": {"url": "https://d16qq0o35va7kz.cloudfront.net/images/Google_113059840438576948815/1781648560823_01KV98F4NQ6F1812VFXAARTTG8.image.png", "type": "image", "prompt": null, "description": "Ben 10 themed alien campfire with green flames and crystal rocks, cartoon style", "subtype": null, "aspect_ratio": [731, 951], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "ben10_bed": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_bed_028a074f-a190-4068-b66b-4dc68c61b95c.webp", "type": "image", "prompt": "Generate a futuristic alien sleeping pod for a Ben 10 themed game. It is a sleek black and green tech bed with Omnitrix green glowing trim around the edges and a dark surface with subtle alien tech patterns. The design is inspired by alien spaceship technology. Full-body, top-down angled view, transparent background, bold chunky cartoon Ben 10 art style, clean thick outlines, game-ready asset, high resolution.", "description": "A futuristic alien sleeping pod in Ben 10 tech style", "subtype": "object", "aspect_ratio": [705, 930], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "ben10_radar": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_radar_d5eafa28-1424-4d79-8da8-e62ef7857471.webp", "type": "image", "prompt": "Generate a futuristic alien radar tower for a Ben 10 themed game. The asset features a compact black metallic body with glowing green Omnitrix energy lines and a rotating green holographic scanner dish on top. Top-down angled view, bold chunky cartoon style, high-quality game asset, transparent background, clean lines, vibrant bioluminescent green accents.", "description": "A futuristic Ben 10 themed alien radar tower with glowing green tech details.", "subtype": "object", "aspect_ratio": [544, 1005], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "ben10_spear": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_spear_7fdab2aa-699c-4032-8690-f76d6d2c20fb.webp", "type": "image", "prompt": "Generate a sharp, pointed spear with a Ben 10 / Omnitrix theme. The spear features a long sleek black handle with subtle neon green hexagonal tech markings. The tip is a sharp, elongated crystalline blade that glows with bright neon green Omnitrix energy. Include a subtle green energy glow effect radiating from the sharp tip. Top-down angled view, oriented pointing toward the top-right (diagonal). Clean, stylized cartoon aesthetic matching the Ben 10 art style. Transparent background, high resolution, game-ready asset.", "description": "A Ben 10 themed energy spear with a sleek black handle and glowing green tip, designed for a top-down game.", "subtype": "object", "aspect_ratio": [888, 914], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "firewood": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/ben10_fuel_3271e2eb-55d5-430b-9a8a-11d7be7e8227.webp", "type": "image", "prompt": "Generate a pile of firewood logs stacked together in a small pile, inspired by the structure of 'firewood_pile'. The logs should have a Ben 10 / Omnitrix aesthetic: dark brown and black metallic wood texture with glowing neon green energy veins and circuit-like markings running along the surface. Top-down isometric view, chunky blocky design, 3D voxel style to match the existing game assets. Transparent background, high resolution, detailed sci-fi textures, game-ready asset.", "description": "A pile of firewood logs with a Ben 10 alien tech theme and glowing green energy veins.", "subtype": "object", "aspect_ratio": [844, 782], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "bg_forest_music": {"url": "https://d16qq0o35va7kz.cloudfront.net/images/Google_113059840438576948815/1781653548210_01KV9D7B5J0EF7QX44JQV13ERP.\u0627\u0635\u0648\u0627\u062a \u0627\u0644\u063a\u0627\u0628\u0629 \u0644\u064a\u0644\u0627  \u0641\u064a\u062f\u064a\u0648 \u064a\u0633\u0627\u0639\u062f\u0643 \u0639\u0644\u0649 \u0627\u0644\u0646\u0648\u0645 \u0648\u0627\u0644\u0627\u0633\u062a\u0631\u062e\u0627\u0621 Asmr.mp3", "type": "audio", "prompt": null, "description": "Forest night ambient sounds / background music for the game", "subtype": null, "aspect_ratio": null, "compression_suggestion": "original", "duration_secs": 0.0, "loop": null, "animation": null}, "adventure_time_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_skin_c3c33f97-dc72-43ee-aa42-c342a729cb74.webp", "type": "image", "prompt": "Generate a full-body standing illustration of Finn the Human from Adventure Time. He is wearing his iconic white bear hat with small ears, a light blue t-shirt, dark blue shorts, and a green backpack. Style is chibi/cute cartoon with bright colors, clean outlines, and simple shading consistent with the Adventure Time animation. Top-down view, front-facing, transparent background, high resolution, game-ready character asset.", "description": "Finn the Human from Adventure Time in a top-down cartoon style for a playable character.", "subtype": "character", "aspect_ratio": [692, 1196], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "jake_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/jake_skin_9f4b8fb9-9a58-4304-9525-a4469a68ab66.webp", "type": "image", "prompt": "Generate a full-body standing illustration of Jake the Dog from Adventure Time, top-down view. Jake is an orange-yellow stretchy bulldog with big round white eyes, black pupils, floppy jowls, and a friendly expression. Use the iconic Adventure Time 2D cartoon art style with bright solid colors, clean thick black outlines, and simple shading. Match the aesthetic of 'adventure_time_skin'. Transparent background, game-ready asset, professional quality.", "description": "Jake the Dog from Adventure Time for a top-down game character", "subtype": "character", "aspect_ratio": [748, 1118], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "bmo_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/bmo_skin_3dc53ea0-1383-411b-9afe-7d8dacd9ae67.webp", "type": "image", "prompt": "Generate a full-body standing illustration of BMO (Beemo) from Adventure Time. BMO is a small teal handheld game console with a simple happy face on its screen, thin black arms, and short blue legs. Use the Adventure Time cartoon art style with clean lines, flat colors, and simple shading. Top-down view, front-facing, game-ready asset, transparent background, high resolution.", "description": "BMO from Adventure Time as a playable character skin in a top-down cartoon style.", "subtype": "character", "aspect_ratio": [638, 1079], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "bubblegum_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/bubblegum_skin_ecc5fe47-7b90-4fbc-b895-e97808b006f5.webp", "type": "image", "prompt": "Generate a top-down view of Princess Bubblegum from Adventure Time. Character design features long pink bubblegum hair, pink skin, a pink and purple dress, and a small golden tiara with a blue jewel. Full body standing illustration, chibi-influenced cartoon style with clean lines and bright colors matching the Adventure Time aesthetic. Top-down perspective, front-facing, transparent background, professional quality game asset.", "description": "Princess Bubblegum character from Adventure Time for top-down gameplay", "subtype": "character", "aspect_ratio": [496, 841], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "marceline_skin": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/marceline_skin_43a79dbf-88c5-489a-958c-5fb83ccc97cd.webp", "type": "image", "prompt": "Generate a full-body standing illustration of Marceline the Vampire Queen from Adventure Time, top-down view for a 2D game. She has long flowing black hair, pale grey-blue skin, pointed vampire ears, and is wearing a red tank top with dark blue jeans. She is carrying her iconic red axe bass guitar. The art style must perfectly match the Adventure Time cartoon aesthetic with clean lines, bright colors, and simple cel-shading. Front-facing character, transparent background, professional game-ready asset.", "description": "Marceline the Vampire Queen from Adventure Time as a top-down game character", "subtype": "character", "aspect_ratio": [586, 1188], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_grass": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_grass_4a37fd89-fedd-4eb8-a101-e2699a78f776.webp", "type": "image", "prompt": "Generate a fully tileable grass texture in the Adventure Time cartoon art style, designed to repeat seamlessly in both horizontal and vertical directions. Bright vibrant green grass with simple cartoon texture patterns, small scattered flowers, and minimal grass blades. Land of Ooo aesthetic with a flat cartoon look, soft shading, and clean lines. No visible seams, suitable for an infinite terrain texture in a top-down game.", "description": "Seamless tileable ground texture in Adventure Time cartoon style for the Land of Ooo aesthetic.", "subtype": "ground", "aspect_ratio": [1024, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_tree_1": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_tree_1_8e8ce64a-7751-4aa2-889b-95c8980c75d2.webp", "type": "image", "prompt": "Generate a whimsical tree in the Adventure Time cartoon style, top-down angled view. Featuring a bright green puffy round canopy and a simple brown cartoon trunk. Land of Ooo aesthetic with vibrant colors, clean outlines, and simple cartoon shading. High quality game-ready asset, transparent background, top-down perspective.", "description": "A whimsical cartoon tree in the Adventure Time style for a top-down survival environment.", "subtype": "object", "aspect_ratio": [803, 944], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_tree_2": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_tree_2_eadaea85-19bf-4932-8f64-c2dd77d80fc5.webp", "type": "image", "prompt": "Generate a candy-themed tree in Adventure Time cartoon style, top-down angled view. Pink and purple candy floss leaves and canopy on a brown striped candy-cane like trunk. Land of Ooo aesthetic, vibrant colors, clean outlines, simple flat cartoon shading, transparent background, game-ready asset. Match the artistic style of image 1.", "description": "A candy-themed tree from the Candy Kingdom in Adventure Time cartoon style for a top-down game.", "subtype": "object", "aspect_ratio": [873, 1007], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_tree_3": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_tree_3_460af20c-2558-4358-b29b-629229d36a9c.webp", "type": "image", "prompt": "Generate a tall blue-green magical tree in Adventure Time cartoon style, top-down angled view. Ice-blue leaves with sparkles, resembling the Ice Kingdom aesthetic. Cool blue and white color palette, clean cartoon outlines, simple flat shading. Professional game-ready asset, transparent background, high resolution.", "description": "A magical blue-green ice tree in the Adventure Time art style for the Ice Kingdom area.", "subtype": "object", "aspect_ratio": [606, 1168], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_wolf": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_wolf_4e914fab-2880-4c95-be81-625802a08552.webp", "type": "image", "prompt": "Generate a top-down angled view illustration of Gunter the penguin from Adventure Time as an enemy creature. Small black and white penguin with an angry expression and bright red glowing eyes, wearing a tiny golden crown. Use the Adventure Time cartoon art style with vibrant colors, thick clean outlines, and simple flat shading. Full body character illustration, transparent background, game-ready asset, high resolution.", "description": "An evil Gunter the penguin enemy in Adventure Time cartoon style with glowing red eyes.", "subtype": "character", "aspect_ratio": [603, 790], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_bear": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_bear_b5e67daa-8241-4f52-a076-0bf9e2399fa0.webp", "type": "image", "prompt": "Generate a large evil monster inspired by the Lich from Adventure Time. The creature is a big green undead-like monster with glowing green eyes, dark horns, and a muscular build. Top-down angled view, full body illustration. Adventure Time cartoon art style with vibrant but menacing colors, clean bold outlines, and simple cartoon shading. Transparent background, professional game-ready asset for a survival game.", "description": "A large green Lich-like monster with glowing eyes and horns, Adventure Time cartoon style", "subtype": "character", "aspect_ratio": [969, 1321], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_frog": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_frog_38ba6981-f1f4-4e25-938d-3e61ac48285c.webp", "type": "image", "prompt": "Generate a small living candy corn creature with thin black legs and a mischievous expression, Adventure Time cartoon style, Land of Ooo aesthetic. Top-down angled view, bright pastel yellow and orange colors, clean bold outlines, simple cartoon shading, transparent background, game-ready asset, high resolution", "description": "A small candy-themed creature in Adventure Time style, replacing a frog", "subtype": "character", "aspect_ratio": [637, 805], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_campfire": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_campfire_c112368b-72ac-4e8a-9d02-24034fa74373.webp", "type": "image", "prompt": "Generate a campfire in the Adventure Time cartoon art style, top-down angled view. The asset features stylized wooden logs arranged in a circle with bright orange and yellow flickering cartoon flames. Land of Ooo aesthetic: vibrant colors, bold clean outlines, simple cel-shading, and a cozy whimsical feel. Transparent background, game-ready asset, high resolution, professional quality illustration.", "description": "A whimsical campfire in the Adventure Time cartoon style for the Land of Ooo environment", "subtype": "object", "aspect_ratio": [882, 839], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_axe": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_axe_a8471939-9478-4b4a-a8eb-9ace7815dabf.webp", "type": "image", "prompt": "Generate a game-ready asset of Finn's golden sword from Adventure Time. The sword features a classic golden blade with a hilt containing a small blue circular gem. Design it in a clean, vibrant cartoon style matching the Adventure Time aesthetic with bold outlines and simple shading. Top-down angled view, blade pointing towards the top-right, right-facing orientation. High resolution, transparent background.", "description": "Finn's golden sword from Adventure Time with a blue gem handle, top-down angled view.", "subtype": "object", "aspect_ratio": [747, 1058], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_spear": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_spear_092f5c65-d4b9-49e4-8c38-695713e1f660.webp", "type": "image", "prompt": "Generate a magical spear weapon in Adventure Time cartoon style. The spear features a long, smooth wooden handle and a sharp, glowing blue crystal tip. Use clean, bold cartoon outlines and bright, vibrant colors matching the Land of Ooo aesthetic. Top-down angled view, diagonal orientation pointing towards the top-right. High resolution, professional game-ready asset on a transparent background.", "description": "A magical blue crystal spear in Adventure Time cartoon style for top-down combat.", "subtype": "object", "aspect_ratio": [825, 929], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_rock": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_rock_97c4b689-8e1d-4b01-95f5-46b95d9a13a5.webp", "type": "image", "prompt": "Generate a top-down view of a grey rounded rock with a simple cute face drawn on it, Adventure Time cartoon style, Land of Ooo aesthetic, thick clean black outlines, flat colors with minimal soft shading, transparent background, game-ready asset, high quality", "description": "A grey cartoon rock with a cute face in the Adventure Time art style", "subtype": "object", "aspect_ratio": [917, 839], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_flower": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_flower_56a3f07f-79f7-470a-95b3-b29628f2acef.webp", "type": "image", "prompt": "Generate a cute cartoon flower in Adventure Time style, top-down view. The flower features bright pink and yellow petals with a simple smiling face in the center, and a thin green stem. Land of Ooo aesthetic: vibrant colors, clean thick outlines, flat cartoon shading, and a whimsical feel. Full-body illustration, transparent background, professional game-ready asset, high resolution.", "description": "A cute smiling cartoon flower in the Adventure Time art style for environmental decoration", "subtype": "other", "aspect_ratio": [569, 823], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_workstation": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_workstation_be4bb9d6-f03e-4da5-a52d-9b2bb13e6c09.webp", "type": "image", "prompt": "Generate a crafting workbench in Adventure Time cartoon style, top-down angled view. The asset should be a wooden table with various whimsical tools, colorful potions, and gadgets scattered on top, reminiscent of Finn and Jake's treehouse workshop. Use bright, vibrant colors, clean thick cartoon outlines, and simple flat shading. Transparent background, high resolution, game-ready illustration.", "description": "A crafting workbench in Adventure Time cartoon style for a top-down game", "subtype": "object", "aspect_ratio": [1410, 950], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_bed": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_bed_d3d2bede-a66e-4825-89d7-eff0338bace4.webp", "type": "image", "prompt": "Generate a cozy treehouse bed in the Adventure Time cartoon style, top-down angled view. The bed features a simple wooden frame with a bright blue and green blanket, resembling Finn and Jake's bedroom. Clean, bold cartoon outlines, vibrant colors, and soft cell shading. High resolution, professional game asset, transparent background.", "description": "A cozy treehouse bed in the Adventure Time cartoon style for a top-down survival game.", "subtype": "object", "aspect_ratio": [936, 816], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_radar": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_radar_94ccec64-0637-43ad-b45f-e25a6be39b2c.webp", "type": "image", "prompt": "Generate a magical radar/telescope tower in the Adventure Time cartoon art style, top-down angled view. The asset features a tall, slightly wonky wooden pole with a large, glowing blue crystal orb on top. Use clean, bold cartoon outlines, vibrant colors, and simple cel-shading characteristic of the Land of Ooo. Professional quality game asset, transparent background, front-facing but with perspective depth.", "description": "A magical crystal radar tower in Adventure Time cartoon style for top-down gameplay", "subtype": "object", "aspect_ratio": [400, 1127], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_wardrobe": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_wardrobe_f18a9e7d-aadc-4df3-81ff-439ee81fae69.webp", "type": "image", "prompt": "Generate a top-down angled view of a wooden wardrobe in the Adventure Time cartoon art style. The wardrobe is made of light-colored wood with a yellow star decoration on the door. One door is slightly ajar, revealing vibrant, colorful clothes inside. Clean, bold cartoon outlines, flat colors with soft cel-shading, consistent with the Land of Ooo aesthetic. High quality game-ready asset on a transparent background.", "description": "A whimsical wooden wardrobe in Adventure Time cartoon style for a top-down game.", "subtype": "object", "aspect_ratio": [782, 968], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_firewood": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_firewood_af353e95-065e-4a5d-b61e-49c00168339a.webp", "type": "image", "prompt": "Generate a pile of cartoon firewood logs in Adventure Time style, top-down view. Simple brown logs stacked together with thick clean cartoon outlines. Bright, simple, colorful design matching the Land of Ooo aesthetic. Professional game-ready asset, high quality, transparent background, top-down angled view.", "description": "A pile of firewood logs in the Adventure Time cartoon style for the Land of Ooo environment.", "subtype": "object", "aspect_ratio": [1050, 884], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_skateboard": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_skateboard_5da0b5bd-75b6-4b47-b503-1ee5ce60e6ea.webp", "type": "image", "prompt": "Generate a skateboard in the Adventure Time cartoon art style, top-down angled view. The skateboard features a bright blue deck with a bold yellow lightning bolt design, matching Finn the Human's color palette. Clean black outlines, vibrant flat colors, and simple cartoon shading. Show the deck and the wheels from a high-angle perspective. Transparent background, professional game-ready asset, high resolution, Land of Ooo aesthetic.", "description": "A Finn-themed blue and yellow skateboard in the Adventure Time cartoon style for top-down gameplay.", "subtype": "object", "aspect_ratio": [454, 1248], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "adventure_time_meat": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/adventure_time_meat_e2d60562-811a-4380-83d4-2fabc82f1aad.webp", "type": "image", "prompt": "Generate a cartoon meat leg drumstick in the Adventure Time art style. Features a classic thick pinkish-red meat section with a white bone handle. Simple flat cartoon design, clean bold outlines, vibrant colors, soft simple shading. Top-down angled view, transparent background, professional game-ready asset, high resolution, matching the visual style of the Land of Ooo.", "description": "A cartoon meat drumstick on a bone in the Adventure Time art style for a top-down game.", "subtype": "object", "aspect_ratio": [711, 1241], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "sb_grass": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_grass_6989b441-8fc1-4e35-b888-a5a3452529cd.webp", "type": "image", "prompt": "Generate a fully tileable sandy ocean floor texture in the SpongeBob SquarePants cartoon style, designed to repeat seamlessly in both horizontal and vertical directions. Light golden-brown sand with small stylized pebbles, tiny shells, and subtle ripple patterns. Warm sandy tones with hints of coral pink and sea green. Top-down view, clean cartoon aesthetic, no visible seams at the edges, suitable for infinite terrain tiling in a 2D game.", "description": "Seamless tileable ocean floor texture for a SpongeBob SquarePants themed environment", "subtype": "ground", "aspect_ratio": [1536, 1024], "compression_suggestion": "original", "duration_secs": null, "loop": null, "animation": null}, "sb_tree_1": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_tree_1_e10df46a-5520-47e3-a6d4-826464131236.webp", "type": "image", "prompt": "Generate a tall, bright pink coral reef formation in the SpongeBob SquarePants cartoon style. The coral should have chunky, cartoonish branching structures, vibrant pink and magenta colors, and a subtle happy facial expression. Top-down angled view for a game environment, clean bold outlines, flat colors with simple shading, transparent background, game-ready asset, high resolution, underwater Bikini Bottom aesthetic.", "description": "A tall bright pink coral reef formation in SpongeBob SquarePants cartoon style to be used as a tree variant.", "subtype": "object", "aspect_ratio": [869, 1299], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "sb_tree_2": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_tree_2_1062bf0d-1802-4080-a382-6cc66ace2f2f.webp", "type": "image", "prompt": "Generate a tall bright green sea kelp plant in the SpongeBob SquarePants cartoon style. Features chunky cartoonish kelp with wide wavy leaves and a cheerful aesthetic. Use vibrant green colors. Top-down angled view, clean polished game-ready asset, high resolution, transparent background.", "description": "A tall bright green sea kelp plant in SpongeBob SquarePants cartoon style for the underwater environment.", "subtype": "object", "aspect_ratio": [726, 1225], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "sb_tree_3": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_tree_3_5aef74bf-dcc8-4dc0-8519-87867c3b9459.webp", "type": "image", "prompt": "Generate a large, chunky cartoon sea anemone in the SpongeBob SquarePants art style. The anemone should have bright orange and purple tentacles waving upward and a friendly smiling face. Top-down angled view, vibrant colors, clean thick outlines, game-ready asset for a Bikini Bottom underwater aesthetic. High resolution, detailed cartoon shading, transparent background.", "description": "A colorful sea anemone tree-substitute in SpongeBob SquarePants cartoon style.", "subtype": "background", "aspect_ratio": [950, 931], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "sb_rock": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_rock_ddce385c-9de9-40a6-940f-a26b9e2688c7.webp", "type": "image", "prompt": "Generate a chunky cartoon-style underwater rock or boulder inspired by the SpongeBob SquarePants aesthetic. The rock is grey-brown and covered with small barnacles and tiny colorful shells. Top-down angled view for a game asset, clean lines, vibrant colors, game-ready, high resolution, transparent background.", "description": "An underwater rock with barnacles in the SpongeBob SquarePants cartoon style, top-down view.", "subtype": "object", "aspect_ratio": [1018, 899], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "sb_flower": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_flower_bc07a7a1-fa1f-4464-8d66-79288ca7c6c2.webp", "type": "image", "prompt": "Generate a cute cartoon starfish decoration in SpongeBob SquarePants art style. Bright orange and pink textured body with a happy smiling face, big expressive eyes, chunky cartoon design. Top-down view, game-ready asset, high resolution, detailed linework, transparent background.", "description": "A cute cartoon starfish decoration in SpongeBob style to replace environmental flowers.", "subtype": "object", "aspect_ratio": [931, 932], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "sb_wolf": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_wolf_4e16a46b-98b7-4fa5-b715-a47d246eea6f.webp", "type": "image", "prompt": "Generate a scary cartoon jellyfish enemy in SpongeBob SquarePants style. Large pink jellyfish with glowing red angry eyes, blue electric tentacles dangling below, menacing expression. 3D chunky cartoon look, top-down angled view, transparent background, game-ready enemy asset. Match the Bikini Bottom aesthetic of image 1.", "description": "A scary pink jellyfish enemy with glowing red eyes in SpongeBob cartoon style.", "subtype": "character", "aspect_ratio": [640, 1081], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "sb_bear": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_bear_637521df-ddb7-45f6-a350-3cdf5e530a2e.webp", "type": "image", "prompt": "Generate a large scary anglerfish sea monster enemy in SpongeBob SquarePants cartoon style. Big dark blue anglerfish with huge sharp teeth, glowing red eyes, and a glowing lure antenna on its head. Menacing and chunky cartoon design with bold outlines. Top-down angled view, standing illustration, high resolution, game-ready asset with a transparent background. Bikini Bottom underwater aesthetic.", "description": "A large scary anglerfish sea monster enemy in SpongeBob SquarePants cartoon style.", "subtype": "character", "aspect_ratio": [756, 953], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "sb_frog": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_frog_c338dc63-0d48-4262-9f8b-912a9d27d66f.webp", "type": "image", "prompt": "Generate a small cute cartoon sea snail in the SpongeBob SquarePants art style. It features a small pink body, a rounded red shell with a darker red spiral pattern, and a single large eye on a stalk with an innocent expression. Top-down angled view, chunky cartoon design, vibrant colors, clean thick outlines, transparent background, game-ready asset, Bikini Bottom underwater aesthetic.", "description": "A cute cartoon sea snail enemy in the SpongeBob SquarePants style, resembling Gary the Snail.", "subtype": "character", "aspect_ratio": [836, 807], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "sb_campfire": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_campfire_d42f6afa-3d16-4e10-a6af-52c1891e92d7.webp", "type": "image", "prompt": "Generate a Krusty Krab fry cook grill in the SpongeBob SquarePants cartoon style. A chunky, stylized cooking grill with bright orange and yellow cartoon flames, a krabby patty burger sizzling on the grates, surrounded by a ring of underwater rocks. Top-down angled view, vibrant colors, clean thick outlines, game-ready asset, transparent background, high resolution, Bikini Bottom aesthetic.", "description": "A Krusty Krab style cooking grill with a sizzling patty and cartoon flames, serving as a campfire.", "subtype": "object", "aspect_ratio": [917, 976], "compression_suggestion": "low", "duration_secs": null, "loop": null, "animation": null}, "sb_axe": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_axe_1bfcd330-baab-4e85-989f-0614374fc08a.webp", "type": "image", "prompt": "Generate a cartoon cooking spatula in the SpongeBob SquarePants art style. Shiny silver metallic spatula head with a brown wooden handle, sparkly and clean highlights, chunky cartoonish design. Top-down view, the spatula head faces right and the handle is oriented vertically. Professional game-ready asset, transparent background, bright and vibrant Bikini Bottom aesthetic.", "description": "A SpongeBob-themed spatula tool serving as an axe in a chunky cartoon style", "subtype": "object", "aspect_ratio": [893, 1315], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "sb_spear": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_spear_7dce6174-41d9-4fc8-ad68-900a88bd6174.webp", "type": "image", "prompt": "Generate a cartoon underwater trident spear in SpongeBob SquarePants style. The trident is golden with three sharp prongs glowing with blue ocean energy, attached to a long wooden handle. High-quality chunky cartoonish design, top-down angled view, diagonal top-right orientation. Transparent background, game-ready asset, Bikini Bottom aesthetic.", "description": "A cartoon underwater trident in SpongeBob SquarePants style for top-down combat.", "subtype": "object", "aspect_ratio": [877, 865], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "sb_workstation": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_workstation_a3741543-2966-4756-9865-2a239d7e05c2.webp", "type": "image", "prompt": "Generate a Krusty Krab kitchen workstation and crafting table in SpongeBob SquarePants cartoon style. The asset should be a chunky cartoon kitchen counter featuring a prominent anchor logo on the front, cooking tools hanging from the side, and yellow sponge-shaped decorative details. Use a vibrant color palette of red and yellow. Top-down angled view, clean outlines, high resolution, professional quality game asset, transparent background, Bikini Bottom aesthetic.", "description": "A Krusty Krab kitchen workstation for crafting in SpongeBob SquarePants cartoon style", "subtype": "object", "aspect_ratio": [964, 932], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "sb_bed": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_bed_7f247064-fc97-4361-a079-ae899b56a83b.webp", "type": "image", "prompt": "Generate a cozy cartoon bed in the SpongeBob SquarePants art style. The bed features a small yellow frame styled like a pineapple's interior, a soft white pillow, and a blanket with a tropical flower pattern. Use a chunky cartoon aesthetic consistent with Bikini Bottom. Top-down angled view showing depth, high quality, clean lines, professional game asset, transparent background.", "description": "A cozy Pineapple-themed bed for the SpongeBob-style underwater setting", "subtype": "object", "aspect_ratio": [826, 924], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "sb_radar": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_radar_7ff1a38d-8e52-4352-b81c-75000f17b2d9.webp", "type": "image", "prompt": "Generate a cartoon underwater sonar radar tower in the SpongeBob SquarePants art style. The asset features a chunky, stylized radar dish mounted on a pink coral tower base. Glowing blue sonar waves are emitting from the dish. Decorated with small anchors and bubble motifs. Top-down angled perspective, 3D chunky cartoon appearance, vibrant Bikini Bottom aesthetic, clean lines, professional game-ready asset, transparent background.", "description": "A cartoon underwater sonar radar tower in SpongeBob SquarePants style with glowing blue waves.", "subtype": "object", "aspect_ratio": [630, 1374], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "sb_wardrobe": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_wardrobe_3f711234-e152-4813-8b1c-dca6cbf1ecce.webp", "type": "image", "prompt": "Generate a cartoon wardrobe or closet in the SpongeBob SquarePants art style. The wardrobe is made of wood but decorated to look like SpongeBob's iconic outfit, featuring a brown lower section with a black belt and silver buckle. It includes a small pink starfish-shaped handle on the door. Chunky cartoonish design, top-down angled view showing depth, bright and vibrant colors, clean lines, transparent background, professional game-ready asset in the Bikini Bottom aesthetic.", "description": "A SpongeBob-themed cartoon wardrobe for the Bikini Bottom environment.", "subtype": "object", "aspect_ratio": [825, 970], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}, "sb_firewood": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_firewood_6615514c-8c5d-4608-85c3-b15a492ddb61.webp", "type": "image", "prompt": "Generate a bundle of kelp and seaweed tied together as fuel in a SpongeBob SquarePants cartoon style. Chunky bundle of bright green kelp strands tied with a simple rope, glowing slightly with a magical underwater effect. Top-down view, clean cartoon lines, vibrant colors, transparent background, game-ready asset. Matches the Bikini Bottom aesthetic of existing sb_ assets.", "description": "A bundle of kelp fuel for a campfire in SpongeBob SquarePants cartoon style", "subtype": "object", "aspect_ratio": [597, 591], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "sb_skateboard": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_skateboard_5b3ad1ca-1a81-46ec-ab99-58c90830264b.webp", "type": "image", "prompt": "Generate a SpongeBob SquarePants themed cartoon skateboard. The deck features a yellow sponge-like texture with SpongeBob's iconic smiling face printed on it. Chunky pink wheels. Top-down angled view showing depth and dimension of the deck and wheels. Bold outlines, vibrant colors, Bikini Bottom cartoon art style. Clean, polished game-ready asset on a transparent background.", "description": "A SpongeBob SquarePants themed cartoon skateboard with a yellow sponge texture and pink wheels.", "subtype": "object", "aspect_ratio": [874, 705], "compression_suggestion": "medium", "duration_secs": null, "loop": null, "animation": null}, "sb_meat": {"url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/sb_meat_c2002356-d5bd-4319-8ceb-59157bfe7325.webp", "type": "image", "prompt": "Generate a cartoon Krabby Patty burger in SpongeBob SquarePants style. A delicious-looking layered burger with a golden bun, green lettuce, red tomato, yellow cheese, and a brown patty. The burger should have a subtle tasty glowing aura. Top-down angled view showing depth, chunky cartoon design, vibrant colors. Transparent background, game-ready asset. Bikini Bottom aesthetic.", "description": "A delicious Krabby Patty burger in the SpongeBob SquarePants cartoon style, used as a food item.", "subtype": "object", "aspect_ratio": [860, 812], "compression_suggestion": "high", "duration_secs": null, "loop": null, "animation": null}}, "game_code": "<!DOCTYPE html>\n<html>\n<head>\n    <title>SpongeBob: Nights in Bikini Bottom</title>\n    <link href=\"https://fonts.googleapis.com/css2?family=Solitreo&display=swap\" rel=\"stylesheet\">\n    <link href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@400&display=swap\" rel=\"stylesheet\">\n    \n    <style>\n        /* CSS Custom Properties */\n        :root {\n            /* Colors - Adventure Time Theme */\n            --color-primary: #0a5a8c;\n            --color-primary-hover: #1a7ab0;\n            --color-accent: #FFD700;\n            --color-accent-hover: #e6c200;\n            --color-background: #031a2e;\n            --color-text: #fffde0;\n            --color-neutral: #1a6b8c;\n            --color-neutral-light: #2a90aa;\n            \n            /* Animation Timings */\n            --transition-fast: 150ms;\n            --transition-normal: 300ms;\n            --transition-slow: 500ms;\n            \n            /* Easing Functions */\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            \n            /* Spacing Scale */\n            --space-xs: 8px;\n            --space-sm: 16px;\n            --space-md: 24px;\n            --space-lg: 32px;\n            --space-xl: 48px;\n            \n            /* Shadows */\n            --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);\n            --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.4);\n            --glow-accent: 0 0 20px rgba(212, 165, 116, 0.3);\n        }\n        \n        /* Reset and Base Styles */\n        body, html { \n            margin: 0; \n            padding: 0; \n            width: 100%; \n            height: 100%; \n            overflow: hidden; \n            font-family: 'Solitreo', cursive;\n            user-select: none;\n            -webkit-user-select: none;\n            -webkit-touch-callout: none;\n            font-size: 16px;\n            line-height: 1.4;\n        }\n        \n        #gameContainer {\n            position: relative;\n            width: 100%;\n            height: 100%;\n            background: #031a2e;\n        }\n        \n        #gameCanvas {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            cursor: default;\n        }\n        \n        /* Main UI Container */\n        #ui {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            pointer-events: none;\n            z-index: 100;\n        }\n        \n        /* Day Counter */\n        #dayCounter {\n            position: absolute;\n            top: var(--space-lg);\n            left: 50%;\n            transform: translateX(-50%);\n            color: #FFD700;\n            font-size: 50px;\n            font-family: 'Solitreo', cursive;\n            pointer-events: none;\n            text-shadow: 0 0 10px #ff9900, 2px 2px 0 #00aaff, -2px -2px 0 #00aaff, 2px -2px 0 #00aaff, -2px 2px 0 #00aaff;\n        }\n        \n        /* Minimap */\n        #minimap {\n            position: absolute;\n            top: 435px;\n            left: 50%;\n            transform: translateX(-50%);\n            width: 120px;\n            height: 120px;\n            background: rgba(0, 0, 0, 0.65);\n            border: none;\n            border-radius: 50%;\n            overflow: hidden;\n            pointer-events: none;\n        }\n        \n        .minimap-dot {\n            position: absolute;\n            border-radius: 50%;\n            pointer-events: none;\n        }\n        \n        .minimap-center {\n            width: 8px;\n            height: 8px;\n            background: #ff4444;\n            box-shadow: 0 0 10px #ff4444;\n        }\n        \n        .minimap-player {\n            width: 6px;\n            height: 6px;\n            background: #00ffff;\n            box-shadow: 0 0 8px #00ffff;\n        }\n        \n        /* Day/Night Overlay */\n        #dayNightOverlay {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            background: rgba(0, 5, 30, 0.65);\n            opacity: 0;\n            pointer-events: none;\n            transition: opacity 5s ease-in-out;\n        }\n        \n        /* Message Area */\n        #messageArea {\n            position: absolute;\n            top: 266px; /* 200px below Day 1 text (66px + 200px) - moved 100px closer */\n            left: 50%;\n            transform: translateX(-50%);\n            width: 80%;\n            max-width: 500px;\n            pointer-events: none;\n            z-index: 110;\n        }\n        \n        .message {\n            color: white;\n            font-size: 34.2px; /* 20% larger than previous (28.5px * 1.2 = 34.2px) */\n            font-family: 'Solitreo', cursive;\n            text-shadow: 2px 2px 0 black, -2px -2px 0 black, 2px -2px 0 black, -2px 2px 0 black;\n            text-align: center;\n            position: absolute;\n            width: 100%;\n            top: 0;\n            left: 0;\n            opacity: 0;\n            transform: scale(0.5);\n        }\n        \n        .message.red {\n            color: #ff4444;\n        }\n        \n        /* Health Bar */\n        #healthBar {\n            position: absolute;\n            top: 120px;\n            left: 50%;\n            transform: translateX(-50%);\n            width: 300px;\n            height: 20px;\n            pointer-events: none;\n        }\n        \n        #healthBarBackground {\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            background: black;\n            border: 1px solid black;\n        }\n        \n        #healthBarFill {\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            background: green;\n            transition: width 0.3s ease-out;\n        }\n        \n        #healthBarLabel {\n            position: absolute;\n            left: -90px;\n            top: 50%;\n            transform: translateY(-50%);\n            color: white;\n            font-size: 24px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 1px 1px 0 black, -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black;\n            pointer-events: none;\n            text-align: right;\n        }\n        \n        /* Hunger Bar */\n        #hungerBar {\n            position: absolute;\n            top: 150px;\n            left: 50%;\n            transform: translateX(-50%);\n            width: 300px;\n            height: 20px;\n            pointer-events: none;\n        }\n        \n        #hungerBarBackground {\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            background: black;\n            border: 1px solid black;\n        }\n        \n        #hungerBarFill {\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            background: orange;\n            transition: width 0.3s ease-out;\n        }\n        \n        #hungerBarLabel {\n            position: absolute;\n            left: -90px;\n            top: 50%;\n            transform: translateY(-50%);\n            color: white;\n            font-size: 24px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 1px 1px 0 black, -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black;\n            pointer-events: none;\n            text-align: right;\n        }\n        \n        /* Fire Bar */\n        #fireBar {\n            position: absolute;\n            top: 180px;\n            left: 50%;\n            transform: translateX(-50%);\n            width: 300px;\n            height: 20px;\n            pointer-events: none;\n        }\n        \n        #fireBarBackground {\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            background: black;\n            border: 1px solid black;\n        }\n        \n        #fireBarFill {\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            background: linear-gradient(90deg, #D94F2B, #E67A4D);\n            transition: width 0.3s ease-out;\n        }\n        \n        #fireBarLabel {\n            position: absolute;\n            left: -90px;\n            top: 50%;\n            transform: translateY(-50%);\n            color: white;\n            font-size: 24px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 1px 1px 0 black, -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black;\n            pointer-events: none;\n            text-align: right;\n        }\n        \n        /* XP Bar (appears near campfire) */\n        #xpBar {\n            position: absolute;\n            width: 300px;\n            height: 20px;\n            pointer-events: none;\n            opacity: 0;\n            transition: opacity 0.5s ease-in-out;\n        }\n        \n        #xpBarBackground {\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            background: black;\n            border: 1px solid black;\n        }\n        \n        #xpBarFill {\n            position: absolute;\n            width: 0%;\n            height: 100%;\n            background: yellow;\n            transition: width 0.3s ease-out;\n        }\n        \n        #xpBarLabel {\n            position: absolute;\n            left: 50%;\n            transform: translateX(-50%);\n            top: -30px;\n            color: white;\n            font-size: 24px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 1px 1px 0 black, -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black;\n            pointer-events: none;\n            text-align: center;\n            white-space: nowrap;\n        }\n        \n        /* Craft Button (appears near workstation) */\n        #craftButton {\n            position: absolute;\n            background: var(--color-primary);\n            color: white;\n            border: 3px solid var(--color-accent);\n            border-radius: 8px;\n            padding: 25px 36px 21px 36px;\n            font-size: 27px;\n            font-family: 'Solitreo', cursive;\n            cursor: pointer;\n            pointer-events: all;\n            opacity: 0;\n            transition: opacity 0.3s ease-in-out, background-color 0.2s ease;\n            z-index: 200;\n            text-shadow: 1px 1px 0 black;\n        }\n        \n        #craftButton:hover {\n            background: var(--color-primary-hover);\n        }\n        \n        #craftButton.visible {\n            opacity: 1;\n        }\n        \n        /* Wardrobe Button (appears near wardrobe) */\n        #wardrobeButton {\n            position: absolute;\n            background: var(--color-primary);\n            color: white;\n            border: 3px solid var(--color-accent);\n            border-radius: 8px;\n            padding: 25px 36px 21px 36px;\n            font-size: 27px;\n            font-family: 'Solitreo', cursive;\n            cursor: pointer;\n            pointer-events: all;\n            opacity: 0;\n            transition: opacity 0.3s ease-in-out, background-color 0.2s ease;\n            z-index: 200;\n            text-shadow: 1px 1px 0 black;\n        }\n        \n        #wardrobeButton:hover {\n            background: var(--color-primary-hover);\n        }\n        \n        #wardrobeButton.visible {\n            opacity: 1;\n        }\n        \n        /* Crafting Dialog Backdrop */\n        #craftingBackdrop {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            background: rgba(0, 0, 0, 0.7);\n            display: none;\n            z-index: 4999;\n            pointer-events: all;\n        }\n        \n        #craftingBackdrop.visible {\n            display: block;\n        }\n        \n        /* Crafting Dialog */\n        #craftingDialog {\n            position: absolute;\n            top: 2%;\n            left: 5%;\n            width: 90%;\n            height: 83.5%;\n            background: radial-gradient(ellipse at center, rgba(10, 70, 130, 0.98) 0%, rgba(3, 30, 70, 0.99) 100%);\n            border: 3px solid var(--color-accent);\n            border-radius: 12px;\n            backdrop-filter: blur(20px);\n            display: none;\n            z-index: 5000;\n            pointer-events: all;\n        }\n        \n        #craftingDialog.visible {\n            display: block;\n        }\n        \n        /* Crafting Grid */\n        #craftingGrid {\n            position: absolute;\n            top: 80px;\n            left: 20px;\n            right: 20px;\n            bottom: 100px;\n            display: grid;\n            grid-template-columns: repeat(3, 1fr);\n            grid-template-rows: repeat(3, 1fr);\n            gap: 15px;\n            padding: 16px;\n        }\n        \n        .craftingItem {\n            background: rgba(212, 165, 116, 0.15);\n            border: 2px solid var(--color-accent);\n            border-radius: 12px;\n            padding: 8px;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: space-between;\n            position: relative;\n        }\n        \n        .craftingItem.owned {\n            border-color: var(--color-neutral);\n            background: rgba(0, 0, 0, 0.4);\n        }\n        \n        .craftingItem.hidden {\n            display: none;\n        }\n        \n        .craftingItemPlaceholder {\n            background: rgba(0, 0, 0, 0.2);\n            border-radius: 12px;\n            padding: 8px;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            position: relative;\n        }\n        \n        .craftingItemName {\n            color: white;\n            font-size: 32px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 1px 1px 0 black;\n            text-align: center;\n            margin-bottom: 4px;\n        }\n        \n        .craftingItemIcon {\n            width: 102px;\n            height: 102px;\n            object-fit: contain;\n            margin: 0px 0;\n        }\n        \n        \n        .craftingItemCostIcon {\n            width: 48px;\n            height: 48px;\n            object-fit: contain;\n            vertical-align: middle;\n        }\n        \n        .craftingItemButton {\n            background: var(--color-primary);\n            color: white;\n            border: 2px solid var(--color-accent);\n            border-radius: 6px;\n            padding: 10px 16px;\n            font-size: 27px;\n            font-family: 'Solitreo', cursive;\n            cursor: pointer;\n            text-shadow: 1px 1px 0 black;\n            transition: background-color 0.2s ease;\n            margin-top: 2px;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            gap: 8px;\n            line-height: 1;\n        }\n        \n        .craftingItemButton:hover:not(:disabled) {\n            background: var(--color-primary-hover);\n        }\n        \n        .craftingItemButton:disabled {\n            opacity: 0.6;\n            cursor: not-allowed;\n        }\n        \n        .craftingItemOwned {\n            color: var(--color-accent);\n            font-size: 25px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 1px 1px 0 black;\n            margin-top: 20px;\n            margin-bottom: 20px;\n        }\n        \n        #craftingHeader {\n            position: absolute;\n            top: 20px;\n            left: 50%;\n            transform: translateX(-50%);\n            color: white;\n            font-size: 48px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 2px 2px 0 black;\n            text-align: center;\n            white-space: nowrap;\n        }\n        \n        #craftingCloseButton {\n            position: absolute;\n            bottom: 15px;\n            left: 50%;\n            transform: translateX(-50%);\n            background: var(--color-primary);\n            color: white;\n            border: 3px solid var(--color-accent);\n            border-radius: 8px;\n            padding: 25px 48px 21px 48px;\n            font-size: 27px;\n            font-family: 'Solitreo', cursive;\n            cursor: pointer;\n            pointer-events: all;\n            text-shadow: 1px 1px 0 black;\n            transition: background-color 0.2s ease;\n        }\n        \n        #craftingCloseButton:hover {\n            background: var(--color-primary-hover);\n        }\n        \n        /* Player Coordinates Display */\n        #playerCoordinates {\n            position: absolute;\n            bottom: 10px;\n            left: 50%;\n            transform: translateX(-50%);\n            color: white;\n            font-size: 12px;\n            font-family: 'Roboto', sans-serif;\n            pointer-events: none;\n            text-align: center;\n        }\n        \n        /* Version Label */\n        #versionLabel {\n            position: absolute;\n            bottom: 10px;\n            left: 10px;\n            color: black;\n            font-size: 12px;\n            font-family: 'Roboto', sans-serif;\n            pointer-events: none;\n            opacity: 0.8;\n        }\n\n        /* Leaderboard Button */\n        #leaderboardBtn {\n            position: absolute;\n            top: 20px;\n            left: 20px;\n            background: rgba(10, 60, 120, 0.85);\n            color: #FFD700;\n            border: 2px solid #FFD700;\n            border-radius: 10px;\n            padding: 12px 20px;\n            font-size: 26px;\n            font-family: 'Solitreo', cursive;\n            cursor: pointer;\n            pointer-events: all;\n            z-index: 200;\n            text-shadow: 0 0 8px #ff9900;\n            box-shadow: 0 0 10px rgba(255,200,0,0.3);\n            transition: background 0.2s ease;\n            user-select: none;\n            white-space: nowrap;\n            min-width: 140px;\n            text-align: center;\n        }\n        #leaderboardBtn:hover { background: rgba(30, 70, 130, 0.95); }\n\n        /* Game Timer */\n        #gameTimer {\n            position: absolute;\n            bottom: 18px;\n            left: 50%;\n            transform: translateX(-50%);\n            color: #FFD700;\n            font-size: 32px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 0 0 8px #00aaff, 1px 1px 0 black, -1px -1px 0 black;\n            pointer-events: none;\n            text-align: center;\n            z-index: 100;\n            display: none;\n        }\n\n        /* Leaderboard Modal */\n        #leaderboardBackdrop {\n            position: absolute;\n            top: 0; left: 0;\n            width: 100%; height: 100%;\n            background: rgba(0,0,0,0.75);\n            display: none;\n            z-index: 6000;\n            pointer-events: all;\n        }\n        #leaderboardBackdrop.visible { display: block; }\n        #leaderboardModal {\n            position: absolute;\n            top: 50%; left: 50%;\n            transform: translate(-50%, -50%);\n            width: 82%;\n            max-height: 85%;\n            background: radial-gradient(ellipse at center, rgba(10,60,120,0.98) 0%, rgba(3,25,50,0.99) 100%);\n            border: 3px solid #FFD700;\n            border-radius: 14px;\n            display: none;\n            flex-direction: column;\n            align-items: center;\n            padding: 32px 28px 28px 28px;\n            z-index: 6001;\n            pointer-events: all;\n            overflow-y: auto;\n            box-sizing: border-box;\n        }\n        #leaderboardModal.visible { display: flex; }\n        #leaderboardTitle {\n            color: #FFD700;\n            font-size: 44px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 0 0 15px #00aaff, 2px 2px 0 black;\n            text-align: center;\n            margin-bottom: 20px;\n        }\n        #leaderboardList { width: 100%; flex: 1; box-sizing: border-box; }\n        .leaderboardRow {\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n            padding: 12px 16px;\n            margin-bottom: 10px;\n            border-radius: 10px;\n            background: rgba(50,100,200,0.2);\n            border: 1px solid rgba(200,180,0,0.3);\n        }\n        .leaderboardRow.top1 { background: rgba(255,215,0,0.2); border-color: gold; }\n        .leaderboardRow.top2 { background: rgba(192,192,192,0.2); border-color: silver; }\n        .leaderboardRow.top3 { background: rgba(205,127,50,0.2); border-color: #cd7f32; }\n        .leaderboardRank { color: #ffcc00; font-size: 28px; font-family: 'Solitreo', cursive; width: 50px; text-align: center; }\n        .leaderboardName { color: white; font-size: 26px; font-family: 'Solitreo', cursive; flex: 1; text-align: center; text-shadow: 1px 1px 0 black; }\n        .leaderboardTime { color: #ffcc00; font-size: 26px; font-family: 'Solitreo', cursive; width: 110px; text-align: right; text-shadow: 0 0 6px #ff9900; }\n        .leaderboardEmpty { color: rgba(255,255,255,0.5); font-size: 28px; font-family: 'Solitreo', cursive; text-align: center; margin-top: 40px; }\n        #leaderboardCloseBtn {\n            background: var(--color-primary);\n            color: white;\n            border: 3px solid var(--color-accent);\n            border-radius: 8px;\n            padding: 18px 48px;\n            font-size: 27px;\n            font-family: 'Solitreo', cursive;\n            cursor: pointer;\n            margin-top: 16px;\n            text-shadow: 1px 1px 0 black;\n            transition: background-color 0.2s ease;\n        }\n        #leaderboardCloseBtn:hover { background: var(--color-primary-hover); }\n\n        /* Language Toggle Button */\n        #langToggleBtn {\n            position: absolute;\n            top: 20px;\n            right: 20px;\n            background: rgba(10, 60, 120, 0.85);\n            color: #FFD700;\n            border: 2px solid #FFD700;\n            border-radius: 10px;\n            padding: 12px 36px;\n            font-size: 26px;\n            font-family: 'Solitreo', cursive;\n            cursor: pointer;\n            pointer-events: all;\n            z-index: 200;\n            text-shadow: 0 0 8px #ff9900;\n            box-shadow: 0 0 10px rgba(255,200,0,0.3);\n            transition: background 0.2s ease;\n            user-select: none;\n            white-space: nowrap;\n            min-width: 140px;\n            text-align: center;\n        }\n        #langToggleBtn:hover {\n            background: rgba(30, 70, 130, 0.95);\n        }\n        \n        /* Inventory */\n        #inventory {\n            position: absolute;\n            bottom: 80px;\n            left: 50%;\n            transform: translateX(-50%);\n            display: flex;\n            gap: var(--space-xs);\n            pointer-events: none;\n            padding-bottom: 28px;\n        }\n        \n        .inventorySlot {\n            width: 94px;\n            height: 94px;\n            background: rgba(0, 0, 0, 0.5);\n            border-radius: 16px;\n            position: relative;\n            pointer-events: all;\n            cursor: pointer;\n            transition: background-color 0.2s ease;\n            overflow: visible;\n        }\n        \n        .inventorySlot:hover {\n            background: rgba(0, 0, 0, 0.7);\n        }\n        \n        .inventorySlot.selected {\n            background: rgba(212, 165, 116, 0.3);\n            border: 2px solid #d4a574;\n        }\n        \n        .inventorySlotLabel {\n            position: absolute;\n            bottom: -24px;\n            left: 50%;\n            transform: translateX(-50%);\n            color: white;\n            font-size: 17px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 1px 1px 0 black, -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black;\n            white-space: nowrap;\n            pointer-events: none;\n            text-align: center;\n        }\n        \n\n        \n        /* Touch Feedback */\n        .touch-feedback {\n            position: absolute;\n            pointer-events: none;\n            border-radius: 50%;\n            background: var(--color-accent);\n            opacity: 0.6;\n            transform: scale(0);\n            animation: touchRipple var(--transition-slow) var(--ease-out) forwards;\n        }\n        \n\n        \n        /* Shadow styling for game objects */\n        .shadow {\n            position: absolute;\n            border-radius: 50%;\n            background: radial-gradient(circle, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0) 100%);\n            pointer-events: none;\n        }\n        \n        /* Animations */\n        @keyframes touchRipple {\n            to {\n                transform: scale(4);\n                opacity: 0;\n            }\n        }\n        \n        @keyframes fadeInUp {\n            to {\n                opacity: 1;\n                transform: translateY(0);\n            }\n        }\n        \n        @keyframes pulse {\n            0%, 100% { transform: scale(1); }\n            50% { transform: scale(1.05); }\n        }\n        \n        /* Reduced Motion Support */\n        @media (prefers-reduced-motion: reduce) {\n            * {\n                animation-duration: 0.01ms !important;\n                animation-iteration-count: 1 !important;\n                transition-duration: 0.01ms !important;\n            }\n        }\n        \n        /* Accessibility Improvements */\n        @media (prefers-contrast: high) {\n            :root {\n                --color-text: #ffffff;\n                --color-background: #000000;\n            }\n        }\n        \n        /* Focus Styles */\n        button:focus-visible {\n            outline: 3px solid var(--color-accent);\n            outline-offset: 2px;\n        }\n    \n        /* Virtual Joystick */\n        #virtualJoystick {\n            width: 120px;\n            height: 120px;\n            border: 2px solid rgba(255, 255, 255, 0.07);\n            border-radius: 50%;\n            background: rgba(74, 124, 89, 0.2);\n            position: absolute;\n            backdrop-filter: blur(8px);\n            box-shadow: var(0 2px 8px rgba(0, 0, 0, 0.3));\n            touch-action: none;\n            -webkit-user-select: none;\n            user-select: none;\n            display: none;\n            opacity: 0.8;\n            z-index: 200;\n            pointer-events: none;\n        }\n        \n        #virtualJoystick.active {\n            display: block;\n        }\n\n        #joystickKnob {\n            position: absolute;\n            width: 50px;\n            height: 50px;\n            background: radial-gradient(circle, #aaaaaa, #808080);\n            border: 2px solid rgba(255, 255, 255, 0.15);\n            border-radius: 50%;\n            top: 50%;\n            left: 50%;\n            margin-top: -25px; /* Half of knob height */\n            margin-left: -25px; /* Half of knob width */\n            transform: translate(0, 0);\n            box-shadow: 0 0 20px rgba(255, 255, 255, 0.3);\n            transition: none;\n            pointer-events: none;\n            will-change: transform;\n            touch-action: none;\n        }\n\n\n        /* Intro Screen */\n        #introScreen {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            background: #021525;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            z-index: 10000;\n            pointer-events: all;\n            opacity: 1;\n            transition: opacity 0.6s ease-out;\n        }\n        \n        #introScreen.fade-out {\n            opacity: 0;\n        }\n        \n        #introText {\n            color: #FFD700;\n            font-size: 48px;\n            font-family: 'Solitreo', cursive;\n            text-align: center;\n            line-height: 1.2;\n            font-weight: bold;\n            text-shadow: 0 0 20px #00aaff, 0 0 40px #0066ff;\n        }\n\n        #loadingText {\n            position: absolute;\n            top: 75%;\n            left: 50%;\n            transform: translateX(-50%);\n            color: rgba(255, 255, 255, 0.5); /* 50% white opacity = half-green appearance */\n            font-size: 36px;\n            font-family: 'Solitreo', cursive;\n            text-align: center;\n            display: none;\n        }\n\n        /* Skill Selection Modal */\n        #skillSelection {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 720px;\n            height: 1280px;\n            background: radial-gradient(ellipse at center, rgba(0, 20, 40, 0.98) 0%, rgba(0, 0, 0, 0.99) 100%);\n            backdrop-filter: blur(20px);\n            display: none;\n            align-items: center;\n            justify-content: center;\n            z-index: 9998;\n            animation: fadeInOverlay 0.4s ease-out;\n            transform-origin: center;\n        }\n\n        /* Wardrobe Dialog */\n        #wardrobeBackdrop {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            background: rgba(0, 0, 0, 0.7);\n            display: none;\n            z-index: 4999;\n            pointer-events: all;\n        }\n\n        #wardrobeBackdrop.visible {\n            display: block;\n        }\n\n        #wardrobeDialog {\n            position: absolute;\n            top: 50%;\n            left: 50%;\n            transform: translate(-50%, -50%);\n            width: 82%;\n            max-height: 85%;\n            background: radial-gradient(ellipse at center, rgba(10, 70, 130, 0.98) 0%, rgba(3, 30, 70, 0.99) 100%);\n            border: 3px solid var(--color-accent);\n            border-radius: 12px;\n            backdrop-filter: blur(20px);\n            display: none;\n            z-index: 5000;\n            pointer-events: all;\n            flex-direction: column;\n            align-items: center;\n            justify-content: flex-start;\n            padding: 32px 28px 28px 28px;\n            overflow-y: auto;\n            box-sizing: border-box;\n        }\n\n        #wardrobeDialog.visible {\n            display: flex;\n        }\n\n        #wardrobeHeader {\n            color: white;\n            font-size: 48px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 2px 2px 0 black;\n            text-align: center;\n            margin-bottom: 20px;\n            white-space: nowrap;\n        }\n\n        #skinGrid {\n            display: grid;\n            grid-template-columns: repeat(2, 1fr);\n            gap: 20px;\n            width: 100%;\n            max-width: 500px;\n            margin-bottom: 20px;\n        }\n\n        .skinOption {\n            background: rgba(212, 165, 116, 0.15);\n            border: 2px solid var(--color-accent);\n            border-radius: 12px;\n            padding: 15px;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            cursor: pointer;\n            transition: all 0.2s ease;\n            min-height: 150px;\n        }\n\n        .skinOption:hover {\n            background: rgba(212, 165, 116, 0.25);\n            transform: scale(1.05);\n        }\n\n        .skinOption.selected {\n            border-color: #00ff00;\n            background: rgba(0, 255, 0, 0.2);\n            box-shadow: 0 0 15px rgba(0, 255, 0, 0.5);\n        }\n\n        .skinPreview {\n            width: 80px;\n            height: 80px;\n            object-fit: contain;\n            margin-bottom: 10px;\n        }\n\n        .skinName {\n            color: white;\n            font-size: 24px;\n            font-family: 'Solitreo', cursive;\n            text-shadow: 1px 1px 0 black;\n            text-align: center;\n        }\n\n        #wardrobeCloseButton {\n            background: var(--color-primary);\n            color: white;\n            border: 3px solid var(--color-accent);\n            border-radius: 8px;\n            padding: 15px 40px;\n            font-size: 27px;\n            font-family: 'Solitreo', cursive;\n            cursor: pointer;\n            pointer-events: all;\n            text-shadow: 1px 1px 0 black;\n            transition: background-color 0.2s ease;\n            margin-top: auto;\n        }\n\n        #wardrobeCloseButton:hover {\n            background: var(--color-primary-hover);\n        }\n    </style>\n</head>\n<body>\n    <div id=\"gameContainer\">\n        <canvas id=\"gameCanvas\"></canvas>\n        \n        <!-- Loading Screen -->\n        <div id=\"introScreen\">\n            <div id=\"introText\">\n                \u0633\u0628\u0648\u0646\u062c \u0628\u0648\u0628!<br>\u0644\u064a\u0627\u0644\u064a \u0628\u064a\u0643\u064a\u0646\u064a \u0628\u0648\u062a\u0648\u0645\n            </div>\n            <div id=\"loadingText\">Loading...</div>\n        </div>\n        \n        <!-- Virtual Joystick (from Last Stand) -->\n        <div id=\"virtualJoystick\">\n            <div id=\"joystickKnob\"></div>\n        </div>\n\n        <div id=\"ui\">\n            <div id=\"dayCounter\">Day 1</div>\n            \n            <div id=\"minimap\">\n                <div class=\"minimap-dot minimap-center\"></div>\n                <div class=\"minimap-dot minimap-player\"></div>\n            </div>\n            \n            <div id=\"messageArea\"></div>\n            \n            <div id=\"healthBar\">\n                <div id=\"healthBarLabel\">Health</div>\n                <div id=\"healthBarBackground\"></div>\n                <div id=\"healthBarFill\"></div>\n            </div>\n            \n            <div id=\"hungerBar\">\n                <div id=\"hungerBarLabel\">Hunger</div>\n                <div id=\"hungerBarBackground\"></div>\n                <div id=\"hungerBarFill\"></div>\n            </div>\n            \n            <div id=\"fireBar\">\n                <div id=\"fireBarLabel\">Fire</div>\n                <div id=\"fireBarBackground\"></div>\n                <div id=\"fireBarFill\"></div>\n            </div>\n            \n            <div id=\"xpBar\">\n                <div id=\"xpBarLabel\">Level 1 progress: 0/100</div>\n                <div id=\"xpBarBackground\"></div>\n                <div id=\"xpBarFill\"></div>\n            </div>\n            \n            <div id=\"inventory\">\n                <div class=\"inventorySlot\">\n                    <img id=\"axeInventoryIcon\" src=\"\" style=\"width: 100%; height: 100%; object-fit: contain; display: none;\">\n                </div>\n                <div class=\"inventorySlot\"></div>\n                <div class=\"inventorySlot\"></div>\n                <div class=\"inventorySlot\"></div>\n                <div class=\"inventorySlot\"></div>\n            </div>\n            \n            <div id=\"playerCoordinates\">X: 0, Y: 1</div>\n            <div id=\"versionLabel\">12.9</div>\n            <button id=\"langToggleBtn\">English</button>\n            <button id=\"leaderboardBtn\">\ud83c\udfc6 \u0635\u062f\u0627\u0631\u0629</button>\n            <div id=\"gameTimer\">00:00</div>\n        </div>\n        \n        <div id=\"dayNightOverlay\"></div>\n        \n        <!-- Craft Button -->\n        <button id=\"craftButton\">Craft</button>\n        \n        <button id=\"wardrobeButton\">Wardrobe</button>\n        \n        <!-- Crafting Backdrop -->\n        <div id=\"craftingBackdrop\"></div>\n        \n        <div id=\"leaderboardBackdrop\"></div>\n        <div id=\"leaderboardModal\">\n            <div id=\"leaderboardTitle\">\ud83c\udfc6 \u0644\u0648\u062d\u0629 \u0627\u0644\u0635\u062f\u0627\u0631\u0629</div>\n            <div id=\"leaderboardList\"></div>\n            <button id=\"leaderboardCloseBtn\">\u0625\u063a\u0644\u0627\u0642</button>\n        </div>\n        \n        <!-- Wardrobe Backdrop -->\n        <div id=\"wardrobeBackdrop\"></div>\n        \n        <!-- Wardrobe Dialog -->\n        <div id=\"wardrobeDialog\">\n            <div id=\"wardrobeHeader\">Choose Your Skin</div>\n            <div id=\"skinGrid\"></div>\n            <button id=\"wardrobeCloseButton\">Done</button>\n        </div>\n        \n        <!-- Crafting Dialog -->\n        <div id=\"craftingDialog\">\n            <div id=\"craftingHeader\">Craft & Upgrade</div>\n            <div id=\"craftingGrid\">\n                <!-- Axe Upgrades (Left Column) -->\n                <div class=\"craftingItem owned\" id=\"craftOldAxe\">\n                    <div class=\"craftingItemName\">Old Axe</div>\n                    <img class=\"craftingItemIcon\" src=\"\" id=\"oldAxeIcon\">\n                    <div class=\"craftingItemOwned\">Owned</div>\n                </div>\n                \n                <div class=\"craftingItem\" id=\"craftGoodAxe\">\n                    <div class=\"craftingItemName\">Good Axe</div>\n                    <img class=\"craftingItemIcon\" src=\"\" id=\"goodAxeIcon\">\n                    <button class=\"craftingItemButton\" id=\"upgradeGoodAxe\">\n                        <img class=\"craftingItemCostIcon\" src=\"\" id=\"woodIconGoodAxe\">\n                        <span id=\"goodAxeCost\">10</span>\n                    </button>\n                </div>\n                \n                <div class=\"craftingItemPlaceholder\" id=\"strongAxePlaceholder\"></div>\n                \n                <div class=\"craftingItem hidden\" id=\"craftStrongAxe\">\n                    <div class=\"craftingItemName\">Strong Axe</div>\n                    <img class=\"craftingItemIcon\" src=\"\" id=\"strongAxeIcon\">\n                    <button class=\"craftingItemButton\" id=\"upgradeStrongAxe\">\n                        <img class=\"craftingItemCostIcon\" src=\"\" id=\"woodIconStrongAxe\">\n                        <span id=\"strongAxeCost\">25</span>\n                    </button>\n                </div>\n                \n                <!-- Center Column (Spear Upgrades) -->\n                <div class=\"craftingItem\" id=\"craftBasicSpear\">\n                    <div class=\"craftingItemName\">Basic Spear</div>\n                    <img class=\"craftingItemIcon\" src=\"\" id=\"basicSpearIcon\">\n                    <button class=\"craftingItemButton\" id=\"upgradeBasicSpear\">\n                        <img class=\"craftingItemCostIcon\" src=\"\" id=\"woodIconBasicSpear\">\n                        <span id=\"basicSpearCost\">15</span>\n                    </button>\n                </div>\n                \n                <div class=\"craftingItemPlaceholder\" id=\"sharpSpearPlaceholder\"></div>\n                \n                <div class=\"craftingItem hidden\" id=\"craftSharpSpear\">\n                    <div class=\"craftingItemName\">Sharp Spear</div>\n                    <img class=\"craftingItemIcon\" src=\"\" id=\"sharpSpearIcon\">\n                    <button class=\"craftingItemButton\" id=\"upgradeSharpSpear\">\n                        <img class=\"craftingItemCostIcon\" src=\"\" id=\"woodIconSharpSpear\">\n                        <span id=\"sharpSpearCost\">30</span>\n                    </button>\n                </div>\n                \n                <div class=\"craftingItemPlaceholder\" id=\"poisonSpearPlaceholder\"></div>\n                \n                <div class=\"craftingItem hidden\" id=\"craftPoisonSpear\">\n                    <div class=\"craftingItemName\" style=\"font-size: 30px;\">Poison Spear</div>\n                    <img class=\"craftingItemIcon\" src=\"\" id=\"poisonSpearIcon\">\n                    <button class=\"craftingItemButton\" id=\"upgradePoisonSpear\">\n                        <img class=\"craftingItemCostIcon\" src=\"\" id=\"woodIconPoisonSpear\">\n                        <span id=\"poisonSpearCost\">50</span>\n                    </button>\n                </div>\n                \n                <!-- Right Column (Skateboard Upgrades) -->\n                <div class=\"craftingItem\" id=\"craftBasicSkateboard\">\n                    <div class=\"craftingItemName\">Skateboard</div>\n                    <img class=\"craftingItemIcon\" src=\"\" id=\"basicSkateboardIcon\">\n                    <button class=\"craftingItemButton\" id=\"upgradeBasicSkateboard\">\n                        <img class=\"craftingItemCostIcon\" src=\"\" id=\"woodIconBasicSkateboard\">\n                        <span id=\"basicSkateboardCost\">20</span>\n                    </button>\n                </div>\n                \n                <div class=\"craftingItemPlaceholder\" id=\"fastSkateboardPlaceholder\"></div>\n                \n                <div class=\"craftingItem hidden\" id=\"craftFastSkateboard\">\n                    <div class=\"craftingItemName\">Fastboard</div>\n                    <img class=\"craftingItemIcon\" src=\"\" id=\"fastSkateboardIcon\">\n                    <button class=\"craftingItemButton\" id=\"upgradeFastSkateboard\">\n                        <img class=\"craftingItemCostIcon\" src=\"\" id=\"woodIconFastSkateboard\">\n                        <span id=\"fastSkateboardCost\">40</span>\n                    </button>\n                </div>\n                \n                <div class=\"craftingItemPlaceholder\" id=\"superSkateboardPlaceholder\"></div>\n                \n                <div class=\"craftingItem hidden\" id=\"craftSuperSkateboard\">\n                    <div class=\"craftingItemName\">Superboard</div>\n                    <img class=\"craftingItemIcon\" src=\"\" id=\"superSkateboardIcon\">\n                    <button class=\"craftingItemButton\" id=\"upgradeSuperSkateboard\">\n                        <img class=\"craftingItemCostIcon\" src=\"\" id=\"woodIconSuperSkateboard\">\n                        <span id=\"superSkateboardCost\">60</span>\n                    </button>\n                </div>\n            </div>\n            <button id=\"craftingCloseButton\">Done</button>\n        </div>\n    </div>\n\n    <script>\n        /* ==================================================\n         * GAME OVERVIEW: 99 Nights in the Forest - A peaceful top-down exploration game where players wander through an infinite procedurally-generated forest. Features smooth omnidirectional movement, chunky voxel-style graphics, and atmospheric drop shadows. Edit mode allows tree placement and density adjustment.\n         * GAME STATE SHAPE: window.gameConfig = {\n         *   player: { startX: number, startY: number },\n         *   world: { treeDensity: number, seed: number },\n         *   ui: { day: number }\n         * }\n         * ==================================================\n         */\n\n        // Asset loading configuration\n        const preloadAssetIds = [\n            'player_character', 'spongebob_skin',\n            'sb_tree_1', 'sb_tree_2', 'sb_tree_3', 'sb_rock',\n            'grass_texture', 'sb_grass', 'sb_firewood',\n            'sb_axe', 'sb_wardrobe', 'sb_campfire'\n        ];\n        \n        const lateLoadAssetIds = [\n            'green_wood_particle', 'brown_wood_particle',\n            'sb_workstation', 'sb_spear', 'sb_skateboard',\n            'sb_wolf', 'sb_meat',\n            'grey_particle', 'red_particle',\n            'sb_bear', 'horror_deer',\n            'sb_axe', 'metal_spear', 'blue_skateboard',\n            'horror_deer_hungry', 'horror_deer_demonic',\n            'sb_flower',\n            'sb_frog',\n            'red_axe', 'minecraft_poison_spear', 'gold_skateboard',\n            'sb_bed', 'sb_radar',\n            'child_1', 'child_2', 'child_3', 'child_4',\n            'patrick_skin', 'squidward_skin', 'mr_krabs_skin', 'sandy_skin'\n        ];\n\n        // Audio system\n        let audioCtx = null;\n        let audioBuffers = {};\n        const audioAssetIds = [\n            'sfx_axe_hit', 'sfx_collect', 'sfx_player_hurt',\n            'sfx_night_warning', 'sfx_levelup', 'sfx_deer_growl',\n            'sfx_campfire', 'sfx_craft', 'bg_forest_music'\n        ];\n\n        // Background music state\n        let bgMusicSource = null;\n        let bgMusicGain = null;\n        let bgMusicPlaying = false;\n\n        // Campfire loop state\n        let campfireLoopSource = null;\n        let campfireLoopPlaying = false;\n        let campfireLoopStarted = false;\n\n        function getAudioContext() {\n            if (!audioCtx) {\n                audioCtx = new (window.AudioContext || window.webkitAudioContext)();\n            }\n            return audioCtx;\n        }\n\n        function loadAudioAssets() {\n            audioAssetIds.forEach(id => {\n                const assetInfo = lib.getAsset(id);\n                if (!assetInfo) return;\n                fetch(assetInfo.url)\n                    .then(r => r.arrayBuffer())\n                    .then(buf => getAudioContext().decodeAudioData(buf))\n                    .then(decoded => { \n                        audioBuffers[id] = decoded; \n                        if (id === 'bg_forest_music' && window.shouldPlayBgMusic) {\n                            startBackgroundMusic();\n                        }\n                    })\n                    .catch(() => {});\n            });\n        }\n\n        function playSound(id, volume = 1.0, loop = false) {\n            try {\n                const ctx = getAudioContext();\n                if (ctx.state === 'suspended') ctx.resume();\n                const buffer = audioBuffers[id];\n                if (!buffer) return null;\n                const source = ctx.createBufferSource();\n                source.buffer = buffer;\n                source.loop = loop;\n                const gainNode = ctx.createGain();\n                gainNode.gain.value = volume;\n                source.connect(gainNode);\n                gainNode.connect(ctx.destination);\n                source.start(0);\n                return { source, gainNode };\n            } catch(e) { return null; }\n        }\n\n        function startCampfireLoop() {\n            if (campfireLoopPlaying || !audioBuffers['sfx_campfire']) return;\n            try {\n                const ctx = getAudioContext();\n                if (ctx.state === 'suspended') ctx.resume();\n                const source = ctx.createBufferSource();\n                source.buffer = audioBuffers['sfx_campfire'];\n                source.loop = true;\n                const gainNode = ctx.createGain();\n                gainNode.gain.value = 0.3;\n                source.connect(gainNode);\n                gainNode.connect(ctx.destination);\n                source.start(0);\n                campfireLoopSource = { source, gainNode };\n                campfireLoopPlaying = true;\n            } catch(e) {}\n        }\n\n        function stopCampfireLoop() {\n            if (!campfireLoopPlaying || !campfireLoopSource) return;\n            try {\n                campfireLoopSource.source.stop();\n            } catch(e) {}\n            campfireLoopSource = null;\n            campfireLoopPlaying = false;\n        }\n\n        function startBackgroundMusic() {\n            if (bgMusicPlaying) return;\n            if (!audioBuffers['bg_forest_music']) {\n                window.shouldPlayBgMusic = true;\n                return;\n            }\n            try {\n                const ctx = getAudioContext();\n                if (ctx.state === 'suspended') ctx.resume();\n                const source = ctx.createBufferSource();\n                source.buffer = audioBuffers['bg_forest_music'];\n                source.loop = true;\n                const gainNode = ctx.createGain();\n                gainNode.gain.value = 0.35;\n                source.connect(gainNode);\n                gainNode.connect(ctx.destination);\n                source.start(0);\n                bgMusicSource = source;\n                bgMusicGain = gainNode;\n                bgMusicPlaying = true;\n                window.shouldPlayBgMusic = false;\n                source.onended = () => { bgMusicPlaying = false; };\n            } catch(e) {}\n        }\n\n        function updateCampfireSound() {\n            if (campfire.fireIntensity > 0.05) {\n                if (!campfireLoopPlaying && audioBuffers['sfx_campfire']) {\n                    startCampfireLoop();\n                }\n                // Adjust volume based on proximity and intensity\n                if (campfireLoopSource) {\n                    const dx = player.x - campfire.x;\n                    const dy = player.y - campfire.y;\n                    const dist = Math.sqrt(dx*dx + dy*dy);\n                    const proximity = Math.max(0, 1 - dist / 400);\n                    campfireLoopSource.gainNode.gain.value = proximity * campfire.fireIntensity * 0.4;\n                }\n            } else {\n                stopCampfireLoop();\n            }\n        }\n\n        let lateAssetsLoaded = false; // Track if late assets are loaded\n\n        // Balance constants\n\n        // First tree arrow position (relative to campfire at 0,0)\n        const FIRST_TREE_ARROW_X = 215;\n        const FIRST_TREE_ARROW_Y = 170;\n\n        const CAMPFIRE_FUEL_PER_WOOD = 0.25;\n        const CAMPFIRE_NEARLY_FULL = 1 - 0.1;\n        const CAMPFIRE_STARTING_INTENSITY = 0.44; // Campfire starting %\n        const CAMPFIRE_STARTING_TIMER = (1 - CAMPFIRE_STARTING_INTENSITY) * 60;\n        const CAMPFIRE_XP_THRESHOLDS = [\n            3,\n            20,\n            40,\n            60,\n            80,\n            999  // Level 6 (max): effectively infinite\n        ];\n        const CAMPFIRE_DECAY_RATES = [\n            1.0,\n            0.8,\n            0.75,\n            0.5,\n            0.4,\n            0.3\n        ];\n        \n        // Upgrade costs\n        const AXE_UPGRADE_COSTS = [\n            0,   // Old (starting equipment)\n            20,  // Good\n            70   // Strong\n        ];\n        const SPEAR_UPGRADE_COSTS = [\n            10,  // Old\n            30,  // Sharp\n            80   // Poison\n        ];\n        const SKATEBOARD_UPGRADE_COSTS = [\n            10,  // Used\n            50,  // New\n            90   // Golden\n        ];\n\n        // Balance stats for axe, spear, and skateboard\n        const AXE_ENVIRONMENT_DAMAGE = [0.9, 1.8, 2.5];  // VS trees/rocks\n        const AXE_ENEMY_DAMAGE = [0.5, 0.8, 1.1];        // VS wolves/bears\n        const SPEAR_ENVIRONMENT_DAMAGE = [0.7, 1.1, 1.5]; // VS trees/rocks  \n        const SPEAR_ENEMY_DAMAGE = [1.0, 1.7, 2.5];      // VS wolves/bears\n        const SKATEBOARD_SPEED_BONUS = [1.4, 1.6, 1.8];  // Speed multiplier\n\n        // Player base movement speed (pixels per second)\n        const MOVEMENT_SPEED = 200;\n        const PLAYER_HUNGRY_SPEED_MULTIPLIER = 0.45;\n        \n        // Deer speed constants\n        const DEER_STALK_SPEED = 80;\n        const DEER_DAY_SPEED_MULTIPLIER = 2;\n        const DEER_NIGHT_SPEED_MULTIPLIER = 2.2;\n        const DEER_FLEE_SPEED_MULTIPLIER = 6;\n        const DEER_HUNGRY_SPEED_MULTIPLIER = 2.09;\n        const DEER_DEMONIC_SPEED_MULTIPLIER = 2.3;\n        \n        // Difficulty radius constants (distance from campfire)\n        const DIFFICULTY_RADIUS = {\n            TRIVIAL: 600,\n            EASY: 2500,\n            MEDIUM: 5500,\n            HARD: 9000,\n            INSANE: 9999999\n        };\n        \n        // Max enemy counts per difficulty level\n        const DIFFICULTY_ENEMY_LIMITS = {\n            TRIVIAL: { wolf: 0, bear: 0 },\n            EASY: { wolf: 1, bear: 0 },\n            MEDIUM: { wolf: 2, bear: 0 },\n            HARD: { wolf: 2, bear: 1 },\n            INSANE: { wolf: 3, bear: 2 }\n        };\n        \n        // Wolf constants\n        const WOLF_SIZE = 150;\n        const WOLF_HEALTH = 5;\n        const WOLF_MOVE_SPEED = 112.5;\n        const WOLF_DAMAGE = 2.5;\n        \n        // Bear constants\n        const BEAR_SIZE = 180;\n        const BEAR_HEALTH = 15;\n        const BEAR_MOVE_SPEED = 210;\n        const BEAR_DAMAGE = 7;\n        \n        // Generic enemy configurations\n        const ENEMY_CONFIGS = {\n            wolf: {\n                size: WOLF_SIZE,\n                health: WOLF_HEALTH,\n                moveSpeed: WOLF_MOVE_SPEED,\n                damage: WOLF_DAMAGE,\n                meatDrops: 1,\n                spawnChance: 0.005,\n                spawnMinTime: 5.0,\n                spawnMaxTime: 10.0\n            },\n            bear: {\n                size: BEAR_SIZE,\n                health: BEAR_HEALTH,\n                moveSpeed: BEAR_MOVE_SPEED,\n                damage: BEAR_DAMAGE,\n                meatDrops: 2,\n                spawnChance: 0.004,\n                spawnMinTime: 7.0,\n                spawnMaxTime: 12.0\n            }\n        };\n        \n        // Frog constants  \n        const FROG_SIZE_MIN = 80;\n        const FROG_SIZE_MAX = 120;\n        const FROG_HEALTH = 3;\n        const FROG_SPEED_MIN = 60;\n        const FROG_SPEED_MAX = 100;\n\n        // Child stats\n        const CHILD_SPAWN_RANGES = [\n            2500,\n            4500,\n            6500,\n            8500\n        ];\n        // Help bubble constants\n        const HELP_BUBBLE_RANGE = 1250;\n        const HELP_BUBBLE_SHOW_TIME = 1.0;\n        const HELP_BUBBLE_HIDE_TIME = 2.0;\n\n        // Game timer\n        let gameTimer = 0;\n\n        function formatTime(seconds) {\n            const m = Math.floor(seconds / 60);\n            const s = Math.floor(seconds % 60);\n            return String(m).padStart(2, '0') + ':' + String(s).padStart(2, '0');\n        }\n\n        function updateGameTimerDisplay() {\n            const el = document.getElementById('gameTimer');\n            if (el) el.textContent = formatTime(gameTimer);\n        }\n\n        // Game state\n        let canvas, ctx;\n        let gameMode = 'play';\n        let assetCache = {};\n        let lastTime = 0;\n        let isGameRunning = true; // Flag to control game loop\n        let introScreenActive = true; // Flag to track intro screen state\n        \n        // Runtime state (not in gameConfig)\n        let player = { \n            x: 0, y: 0, targetX: 0, targetY: 0, size: 120, facingRight: true, // Fixed: start facing right\n            bounceTimer: 0, isMoving: false, bounceHeight: 0,\n            originalBounceHeight: 0, // Store original bounce for skateboard comparison\n            health: 100, maxHealth: 100,\n            hunger: 100, maxHunger: 100, hungerTimer: 0,\n            level: 1, xp: 0, maxXp: 100,\n            // For tracking movement speed\n            lastX: 0, lastY: 0, currentSpeed: 0\n        };\n        \n        // Current weapon selection\n        let currentWeapon = 'axe'; // 'axe' or 'spear'\n        let axeLevel = 'old'; // 'old', 'good', or 'strong'\n        let spearLevel = 0; // 0 = no spear, 1 = basic, 2 = sharp, 3 = poison\n        let hasSpear = false; // Player must craft spear\n        \n        // Helper function to get axe level index for damage arrays\n        function getAxeLevelIndex() {\n            switch (axeLevel) {\n                case 'old': return 0;\n                case 'good': return 1;\n                case 'strong': return 2;\n                default: return 0;\n            }\n        }\n        \n        // Helper function to get axe asset ID based on level\n        function getAxeAssetId(level) {\n            switch (level) {\n                case 'old': return 'sb_axe';\n                case 'good': return 'sb_axe';\n                case 'strong': return 'red_axe';\n                default: return 'sb_axe'; // fallback\n            }\n        }\n        \n        // Helper function to get spear level index for damage arrays\n        function getSpearLevelIndex() {\n            return Math.max(0, spearLevel - 1); // Convert 1-3 to 0-2\n        }\n        \n        // Helper function to get spear asset ID based on level\n        function getSpearAssetId(level) {\n            if (level === 1) return 'sb_spear';\n            if (level === 2) return 'sb_spear';\n            if (level === 3) return 'minecraft_poison_spear';\n            return 'sb_spear'; // fallback\n        }\n        \n        // Skateboard system\n        let hasSkateBoard = false; // Player must craft skateboard\n        let skateboardEquipped = false;\n        let skateboardLevel = 0; // 0 = no skateboard, 1 = basic, 2 = fast, 3 = super\n        \n        // Helper function to get skateboard asset ID based on level\n        function getSkateboardAssetId(level) {\n            if (level === 1) return 'sb_skateboard';\n            if (level === 2) return 'blue_skateboard';\n            if (level === 3) return 'gold_skateboard';\n            return 'sb_skateboard'; // fallback\n        }\n        \n        // Wolf system\n        let wolves = [];\n        let wolfDamageCooldowns = new Map(); // Track damage cooldowns for each wolf\n        \n        // Bear system\n        let bears = [];\n        let bearDamageCooldowns = new Map(); // Track damage cooldowns for each bear\n        \n        // Enemy spawn timing tracking\n        let lastEnemySpawnTime = {\n            wolf: 0,\n            bear: 0\n        };\n        \n        // Generic enemy system functions\n        function getEnemyArray(enemyType) {\n            switch(enemyType) {\n                case 'wolf': return wolves;\n                case 'bear': return bears;\n                default: throw new Error(`Unknown enemy type: ${enemyType}`);\n            }\n        }\n        \n        function getEnemyDamageCooldowns(enemyType) {\n            switch(enemyType) {\n                case 'wolf': return wolfDamageCooldowns;\n                case 'bear': return bearDamageCooldowns;\n                default: throw new Error(`Unknown enemy type: ${enemyType}`);\n            }\n        }\n        \n        function spawnGenericEnemy(enemyType) {\n            // Don't spawn bear if asset hasn't loaded yet\n            if (enemyType === 'bear' && (!assetCache['bear'] || !assetCache['bear'].complete)) {\n                return;\n            }\n\n            const config = ENEMY_CONFIGS[enemyType];\n            const enemyArray = getEnemyArray(enemyType);\n            \n            // Never spawn if there are already max enemies for current difficulty\n            const activeEnemies = enemyArray.filter(enemy => !enemy.destroyed && !enemy.fullyDestroyed);\n            const maxEnemiesForDifficulty = getMaxEnemiesForCurrentDifficulty(enemyType);\n            \n            if (activeEnemies.length >= maxEnemiesForDifficulty) return;\n            \n            // Spawn enemy just beyond screen edge, but within despawn range (800px)\n            const spawnDistance = 720;\n            let angle;\n            \n            // Check if player is moving to spawn in front of them\n            if (player.isMoving) {\n                // Calculate player's movement direction using position history\n                const moveDx = player.x - player.lastX;\n                const moveDy = player.y - player.lastY;\n                const moveDistance = Math.sqrt(moveDx * moveDx + moveDy * moveDy);\n                \n                if (moveDistance > 0) {\n                    // Get player's movement angle and spawn in front (same direction as movement)\n                    const moveAngle = Math.atan2(moveDy, moveDx);\n                    // Add some randomness (\u00b145 degrees) to the front direction\n                    const randomOffset = (Math.random() - 0.5) * (Math.PI / 2); // \u00b1\u03c0/4 radians = \u00b145 degrees\n                    angle = moveAngle + randomOffset;\n                } else {\n                    // Fallback to random if movement calculation fails\n                    angle = Math.random() * Math.PI * 2;\n                }\n            } else {\n                // Player is stationary, use original random logic\n                angle = Math.random() * Math.PI * 2;\n            }\n            \n            const spawnX = player.x + Math.cos(angle) * spawnDistance;\n            const spawnY = player.y + Math.sin(angle) * spawnDistance;\n            \n            const enemy = {\n                x: spawnX,\n                y: spawnY,\n                size: config.size,\n                health: config.health,\n                maxHealth: config.health,\n                bounceTimer: 0,\n                bounceHeight: 0,\n                isMoving: true,\n                movingRight: false,\n                shakeTimer: 0,\n                shakeIntensity: 0,\n                healthBarTimer: 0,\n                destroyed: false,\n                fullyDestroyed: false,\n                destructionTimer: 0,\n                destructionDuration: 0.8,\n                destructionScale: 1.0,\n                originalY: spawnY,\n                type: enemyType\n            };\n            \n            enemyArray.push(enemy);\n        }\n        \n        function updateGenericEnemies(enemyType, deltaTime) {\n            const config = ENEMY_CONFIGS[enemyType];\n            const enemyArray = getEnemyArray(enemyType);\n            const damageCooldowns = getEnemyDamageCooldowns(enemyType);\n            \n            // Don't spawn enemies on day 1\n            if (window.gameConfig.ui.day === 1) {\n                return;\n            }\n            \n            // Handle spawning with timing constraints (wolves and bears spawn any time after day 1)\n            const currentTime = Date.now() / 1000; // Convert to seconds\n            const timeSinceLastSpawn = currentTime - lastEnemySpawnTime[enemyType];\n            \n            let shouldSpawn = false;\n            \n            if (timeSinceLastSpawn < config.spawnMinTime) {\n                // Too soon - 0% chance\n                shouldSpawn = false;\n            } else if (timeSinceLastSpawn >= config.spawnMaxTime) {\n                // Too long - 100% chance (guaranteed spawn)\n                shouldSpawn = true;\n            } else {\n                // Between min and max - use normal random chance\n                shouldSpawn = Math.random() < config.spawnChance;\n            }\n            \n            if (shouldSpawn) {\n                spawnGenericEnemy(enemyType);\n                lastEnemySpawnTime[enemyType] = currentTime;\n            }\n            \n            for (let i = enemyArray.length - 1; i >= 0; i--) {\n                const enemy = enemyArray[i];\n                \n                if (enemy.fullyDestroyed) {\n                    enemyArray.splice(i, 1);\n                    continue;\n                }\n                \n                if (enemy.destroyed) {\n                    enemy.destructionTimer += deltaTime;\n                    enemy.destructionScale = Math.max(0, 1.0 - (enemy.destructionTimer / enemy.destructionDuration));\n                    \n                    if (enemy.destructionTimer >= enemy.destructionDuration) {\n                        enemy.fullyDestroyed = true;\n                    }\n                    continue;\n                }\n                \n                // Despawn enemies that are too far from player (over 800px)\n                const despawnDistance = 800;\n                const dx = player.x - enemy.x;\n                const dy = player.y - enemy.y;\n                const distanceToPlayer = Math.sqrt(dx * dx + dy * dy);\n                \n                if (distanceToPlayer > despawnDistance) {\n                    // Remove enemy from array and clean up damage cooldowns\n                    const enemyIndex = enemyArray.indexOf(enemy);\n                    if (enemyIndex !== -1) {\n                        const damageCooldowns = getEnemyDamageCooldowns(enemyType);\n                        damageCooldowns.delete(enemyIndex);\n                        enemyArray.splice(i, 1);\n                    }\n                    continue;\n                }\n                \n                // Bounce animation\n                enemy.bounceTimer += deltaTime * 8;\n                enemy.bounceHeight = Math.abs(Math.sin(enemy.bounceTimer)) * 20;\n                \n                // Movement towards player with campfire protection\n                // Reuse dx, dy from despawn check above\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                \n                if (distance > 5) {\n                    let moveX = dx / distance;\n                    let moveY = dy / distance;\n                    \n                    // Campfire protection logic\n                    const campfireDx = player.x - campfire.x;\n                    const campfireDy = player.y - campfire.y;\n                    const playerCampfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy);\n                    const campfireSafeZone = 280;\n                    \n                    const enemyToCampfireDx = enemy.x - campfire.x;\n                    const enemyToCampfireDy = enemy.y - campfire.y;\n                    const enemyCampfireDistance = Math.sqrt(enemyToCampfireDx * enemyToCampfireDx + enemyToCampfireDy * enemyToCampfireDy);\n                    \n                    // Check if player is in campfire safe zone and fire is lit\n                    const playerInSafeZone = playerCampfireDistance <= campfireSafeZone;\n                    const campfireIsLit = campfire.fireIntensity > 0;\n                    const enemyInSafeZone = enemyCampfireDistance <= campfireSafeZone;\n                    \n                    // If enemy would move into safe zone while player is in safe zone and fire is lit, circle around instead\n                    if (enemyInSafeZone && playerInSafeZone && campfireIsLit) {\n                        // Circle around the safe zone instead of moving toward player\n                        const angleToCampfire = Math.atan2(enemy.y - campfire.y, enemy.x - campfire.x);\n                        const circleAngle = angleToCampfire + Math.PI * 0.5; // 90 degrees offset for circling\n                        moveX = Math.cos(circleAngle);\n                        moveY = Math.sin(circleAngle);\n                    }\n                    \n                    enemy.x += moveX * config.moveSpeed * deltaTime;\n                    enemy.y += moveY * config.moveSpeed * deltaTime;\n                    \n                    enemy.movingRight = moveX > 0;\n                }\n                \n                // Shake animation\n                if (enemy.shakeTimer > 0) {\n                    enemy.shakeTimer -= deltaTime;\n                    if (enemy.shakeTimer <= 0) {\n                        enemy.shakeIntensity = 0;\n                    }\n                }\n                \n                // Health bar timer\n                if (enemy.healthBarTimer > 0) {\n                    enemy.healthBarTimer -= deltaTime;\n                }\n                \n                // Player collision for damage\n                const playerCollisionDistance = (player.size + enemy.size) / 2;\n                if (distance < playerCollisionDistance) {\n                    const enemyId = enemyArray.indexOf(enemy);\n                    if (!damageCooldowns.has(enemyId) || Date.now() - damageCooldowns.get(enemyId) > 1000) {\n                        player.health -= config.damage;\n                        player.healthTimer = 2.0;\n                        damageCooldowns.set(enemyId, Date.now());\n                        updateHealthBar();\n                        \n                        // Shake player\n                        player.shakeTimer = 0.5;\n                        player.shakeIntensity = 40;\n                        \n                        if (player.health <= 0) {\n                            showGameOverScreen();\n                            return;\n                        }\n                    }\n                }\n            }\n        }\n        \n        function getCurrentDifficultyLevel() {\n            // Calculate distance from player to campfire\n            const dx = player.x - campfire.x;\n            const dy = player.y - campfire.y;\n            const distance = Math.sqrt(dx * dx + dy * dy);\n            \n            // Return difficulty level based on distance\n            if (distance <= DIFFICULTY_RADIUS.TRIVIAL) return 'TRIVIAL';\n            if (distance <= DIFFICULTY_RADIUS.EASY) return 'EASY';\n            if (distance <= DIFFICULTY_RADIUS.MEDIUM) return 'MEDIUM';\n            if (distance <= DIFFICULTY_RADIUS.HARD) return 'HARD';\n            return 'INSANE';\n        }\n        \n        function getMaxEnemiesForCurrentDifficulty(enemyType) {\n            const difficultyLevel = getCurrentDifficultyLevel();\n            const limits = DIFFICULTY_ENEMY_LIMITS[difficultyLevel];\n            return limits[enemyType] || 0;\n        }\n        \n        function clearGenericEnemies(enemyType) {\n            const enemyArray = getEnemyArray(enemyType);\n            const damageCooldowns = getEnemyDamageCooldowns(enemyType);\n            enemyArray.length = 0; // Clear the array\n            damageCooldowns.clear(); // Clear the cooldowns\n        }\n        \n        function mapEnemiesToObjects(enemyType) {\n            const enemyArray = getEnemyArray(enemyType);\n            return enemyArray.map(enemy => ({\n                x: enemy.x,\n                y: enemy.y,\n                type: enemyType,\n                size: enemy.size,\n                bounceHeight: enemy.bounceHeight,\n                shakeTimer: enemy.shakeTimer,\n                shakeIntensity: enemy.shakeIntensity,\n                health: enemy.health,\n                maxHealth: enemy.maxHealth,\n                healthBarTimer: enemy.healthBarTimer,\n                destroyed: enemy.destroyed,\n                destructionScale: enemy.destructionScale,\n                originalY: enemy.originalY,\n                fullyDestroyed: enemy.fullyDestroyed,\n                movingRight: enemy.movingRight\n            }));\n        }\n        \n        function checkGenericEnemyCollisions(enemyType) {\n            if (!axe.isSwinging || axe.hasHitThisSwing) return;\n            if (skateboardEquipped) return;\n            \n            const config = ENEMY_CONFIGS[enemyType];\n            const enemyArray = getEnemyArray(enemyType);\n            \n            const axeOffsetX = player.facingRight ? (player.size * 0.5 + 10) : -(player.size * 0.5 + 10);\n            const axeX = player.x + axeOffsetX;\n            const axeY = player.y;\n            const axeSize = 75;\n            \n            enemyArray.forEach(enemy => {\n                if (enemy.destroyed || enemy.fullyDestroyed) return;\n                \n                const dx = axeX - enemy.x;\n                const dy = axeY - enemy.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const collisionDistance = (axeSize + enemy.size) / 2;\n                \n                if (distance < collisionDistance) {\n                    let damage = 1;\n                    if (currentWeapon === 'spear' && hasSpear) {\n                        damage = SPEAR_ENEMY_DAMAGE[getSpearLevelIndex()];\n                    } else {\n                        damage = AXE_ENEMY_DAMAGE[getAxeLevelIndex()];\n                    }\n                    if (player.hunger <= 0) {\n                        damage = Math.ceil(damage * 0.5);\n                    }\n                    \n                    enemy.health -= damage;\n                    enemy.shakeTimer = 0.5;\n                    enemy.shakeIntensity = 30;\n                    enemy.healthBarTimer = 2.0;\n                    \n                    createWolfParticles(axeX, axeY);\n                    axe.hasHitThisSwing = true;\n                    \n                    if (enemy.health <= 0) {\n                        enemy.destroyed = true;\n                        enemy.destructionTimer = 0;\n                        enemy.destructionDuration = 0.8;\n                        enemy.destructionScale = 1.0;\n                        enemy.originalY = enemy.y;\n                        \n                        // Spawn meat drops based on config\n                        for (let i = 0; i < config.meatDrops; i++) {\n                            spawnMeat(enemy.x, enemy.y);\n                        }\n                    }\n                    \n                    return;\n                }\n            });\n        }\n        \n        // Frog system\n        let frogs = [];\n        \n        // Deer system\n        let deer = [];\n        \n        // Firewood collection system\n        let firewoodPiles = [];\n        let firewoodCount = 0;\n        \n        // Meat collection system\n        let meatPiles = [];\n        let meatCount = 0;\n        \n        // Poison spear system\n        let poisonSpears = []; // TODO: May be deprecated\n        let hasPoisonSpear = false;\n        \n        // Child system\n        let children = [];\n        let childrenRescued = 0; // Counter for rescue order\n        \n        // Help bubble state\n        let helpBubbleTimer = 0;\n        let helpBubbleVisible = false;\n        \n        function initializeChildren() {\n            // Create a shuffled copy of CHILD_SPAWN_RANGES\n            const shuffledDistances = [...CHILD_SPAWN_RANGES];\n            for (let i = shuffledDistances.length - 1; i > 0; i--) {\n                const j = Math.floor(Math.random() * (i + 1));\n                [shuffledDistances[i], shuffledDistances[j]] = [shuffledDistances[j], shuffledDistances[i]];\n            }\n            \n            // Place 4 children at fixed distances (from shuffled array) but random angles\n            for (let index = 0; index < 4; index++) {\n                // Use index to get a unique distance from the shuffled array\n                const distance = shuffledDistances[index];\n                // Pick a random angle (0 to 2\u03c0 radians)\n                const angle = Math.random() * Math.PI * 2;\n                // Calculate position relative to campfire (which is at 0,0)\n                const pos = {\n                    x: Math.cos(angle) * distance,\n                    y: Math.sin(angle) * distance\n                };\n                children.push({\n                    id: `child_${index + 1}`,\n                    assetId: `child_${index + 1}`,\n                    x: pos.x,\n                    y: pos.y,\n                    size: 104,\n                    isFollowing: false,\n                    followTarget: null,\n                    rescueOrder: -1, // -1 = not rescued, 0+ = order rescued\n                    followOffset: 96, // Distance to maintain from follow target (increased by 60%)\n                    speed: 0,\n                    targetX: pos.x,\n                    targetY: pos.y,\n                    lastTargetX: pos.x,\n                    lastTargetY: pos.y,\n                    stopDelay: 0.3, // Delay before stopping after target stops\n                    stopTimer: 0,\n                    isMoving: false,\n                    jumpTimer: 0,\n                    jumpPhase: 0,\n                    jumpHeight: 0,\n                    movingRight: false,\n                    isVisible: true\n                });\n            }\n        }\n        \n        // Axe state - simple rotation about center\n        let axe = {\n            rotation: 0,\n            isSwinging: false,\n            swingTimer: 0,\n            swingDuration: 0.2, // 1.5x faster (0.3 / 1.5 = 0.2)\n            hasHitThisSwing: false, // Track if axe has already hit something this swing\n            yOffset: 0 // Downward translation during swing\n        };\n        let camera = { x: 0, y: 0 };\n        let trees = new Map(); // Map of grid coordinates to tree data\n        let rocksAndFlowers = new Map(); // Map of grid coordinates to rock/flower data\n        let input = { \n            keys: {},\n            touch: { active: false, x: 0, y: 0 },\n            mouse: { active: false, x: 0, y: 0 }\n        };\n        \n\n        // Virtual joystick variables (from Last Stand)\n        let joystickActive = false;\n        let joystickTouchId = null;\n        let joystickCenter = { x: 0, y: 0 };\n        let joystickInput = { x: 0, y: 0 };\n        let joystickStartPos = { x: 0, y: 0 };\n        \n        // Create virtual joystick at touch position\n        function createJoystick(x, y, touchId) {\n            const joystick = document.getElementById('virtualJoystick');\n            if (!joystick) return;\n            \n            joystickStartPos.x = x;\n            joystickStartPos.y = y;\n            joystickCenter.x = x;\n            joystickCenter.y = y;\n            \n            // Position joystick at touch location\n            joystick.style.left = (x - 60) + 'px'; // Center the 120px joystick\n            joystick.style.top = (y - 60) + 'px';\n            joystick.classList.add('active');\n            \n            joystickActive = true;\n            joystickTouchId = touchId;\n        }\n        \n        // Handle joystick movement\n        function handleJoystickMove(e) {\n            if (!joystickActive) return;\n            \n            let touch = e;\n            \n            // For touch events, find the correct touch\n            if (e.touches) {\n                touch = null;\n                for (let i = 0; i < e.touches.length; i++) {\n                    if (e.touches[i].identifier === joystickTouchId) {\n                        touch = e.touches[i];\n                        break;\n                    }\n                }\n                if (!touch) return;\n            }\n            \n            const dx = touch.clientX - joystickCenter.x;\n            const dy = touch.clientY - joystickCenter.y;\n            const distance = Math.sqrt(dx * dx + dy * dy);\n            const maxDistance = 35;\n            \n            // Calculate clamped position\n            let clampedX = dx;\n            let clampedY = dy;\n            \n            if (distance > maxDistance) {\n                clampedX = (dx / distance) * maxDistance;\n                clampedY = (dy / distance) * maxDistance;\n            }\n            \n            // Set joystick input values (normalized)\n            joystickInput.x = clampedX / maxDistance;\n            joystickInput.y = clampedY / maxDistance;\n            \n            // Update knob position\n            const joystickKnob = document.getElementById('joystickKnob');\n            if (joystickKnob) {\n                joystickKnob.style.transform = `translate(${clampedX}px, ${clampedY}px)`;\n            }\n        }\n        \n        // Handle joystick release\n        function handleJoystickEnd(e) {\n            if (!joystickActive) return;\n            \n            // For touch events, check if this is the joystick touch ending\n            if (e.changedTouches) {\n                let found = false;\n                for (let i = 0; i < e.changedTouches.length; i++) {\n                    if (e.changedTouches[i].identifier === joystickTouchId) {\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) return;\n            }\n            \n            // Hide joystick\n            joystickActive = false;\n            joystickTouchId = null;\n            \n            const joystick = document.getElementById('virtualJoystick');\n            const joystickKnob = document.getElementById('joystickKnob');\n            \n            if (joystick) {\n                joystick.classList.remove('active');\n            }\n            \n            joystickInput.x = 0;\n            joystickInput.y = 0;\n            \n            // Reset knob to center\n            if (joystickKnob) {\n                joystickKnob.style.transform = 'translate(0, 0)';\n            }\n        }\n        \n        // Day/Night cycle state\n        let dayNightTimer = 0;\n        let isNight = false;\n        let dayNightTransitioning = false;\n        let gameSystemsStarted = false; // Track if game systems (day/night, hunger, fire) have started\n        let anyTreeChopped = false; // Track if any tree has been chopped (for first tree wood guarantee)\n        let firstWoodPickedUp = false; // Track if player has picked up wood for the first time\n        \n        // Campfire state\n        let campfire = {\n            x: 0, y: 0, // Center of world\n            fireParticles: [],\n            smokeParticles: [],\n            fireIntensity: CAMPFIRE_STARTING_INTENSITY,\n            fireTimer: CAMPFIRE_STARTING_TIMER,\n            shadowFlicker: 0,\n            level: 1,\n            xp: 0,\n            maxXp: CAMPFIRE_XP_THRESHOLDS[0], // Use first threshold\n            levelUpEffect: false,\n            levelUpTimer: 0\n        };\n        \n        // Wood transfer animation state\n        let woodTransfers = [];\n        \n        // Meat transfer animation state (for XP)\n        let meatTransfers = [];\n        \n        // Workstation state\n        let workstation = {\n            x: 110, y: -210, // Above and to the right of campfire\n            size: 120\n        };\n        \n        // Bed state\n        let bed = {\n            x: -110, y: 210,\n            size: 150,\n            childrenRescued: 0,\n            maxChildren: 4\n        };\n        \n        // Radar station (enables minimap)\n        let radar = {\n            x: -240, y: -140,\n            size: 297,\n            enabled: false // Becomes true when campfire reaches level 5\n        };\n        \n        // Wardrobe system\n        let wardrobe = {\n            x: 240, y: -140, // To the right of campfire\n            size: 150,\n            enabled: true // Always available\n        };\n        \n        // Available skins\n        const AVAILABLE_SKINS = [\n            { id: 'spongebob_skin', name: 'SpongeBob' },\n            { id: 'patrick_skin', name: 'Patrick' },\n            { id: 'squidward_skin', name: 'Squidward' },\n            { id: 'mr_krabs_skin', name: 'Mr. Krabs' },\n            { id: 'sandy_skin', name: 'Sandy' }\n        ];\n        \n        let currentSkinId = 'spongebob_skin'; // Default skin - SpongeBob\n        \n        // Red arrow animation state\n        let craftingArrow = {\n            visible: false,\n            hidden: false,\n            revealAgainAtLevel4: false,\n            bobTimer: 0,\n            bobSpeed: 4.2,\n            bobHeight: 15\n        };\n\n        // First tree arrow animation state\n        let firstTreeArrow = {\n            visible: true, // Visible from start\n            bobTimer: 0,\n            bobSpeed: 4.2,\n            bobHeight: 15\n        };\n\n        // Campfire arrow animation state\n        let campfireArrow = {\n            visible: false, // Hidden until first tree is chopped\n            bobTimer: 0,\n            bobSpeed: 4.2,\n            bobHeight: 15\n        };\n\n        // Constants\n        const GRID_SIZE = 800; // Size of each grid cell for tree generation (4x spacing)\n        const TREE_TYPES = ['sb_tree_1', 'sb_tree_2', 'sb_tree_3'];\n        const ROCK_FLOWER_TYPES = ['sb_rock', 'sb_flower'];\n        const CAMERA_SMOOTHING = 0.1;\n        \n        // Message system\n        let messageQueue = [];\n        let messageContainer = null;\n        \n        // Touch feedback system\n        function createTouchFeedback(x, y) {\n            const feedback = document.createElement('div');\n            feedback.className = 'touch-feedback';\n            feedback.style.left = (x - 20) + 'px';\n            feedback.style.top = (y - 20) + 'px';\n            feedback.style.width = '40px';\n            feedback.style.height = '40px';\n            document.getElementById('ui').appendChild(feedback);\n            \n            setTimeout(() => {\n                if (feedback.parentNode) {\n                    feedback.parentNode.removeChild(feedback);\n                }\n            }, 500);\n        }\n        \n        // Message system\n        function showMessage(text, isRed = false, customColor = null) {\n            if (!messageContainer) {\n                messageContainer = document.getElementById('messageArea');\n            }\n            \n            // Check if this message matches ANY message in the queue\n            const existingMessage = messageQueue.find(msg => msg.element.textContent === text);\n            \n            if (existingMessage) {\n                // Don't add a new message - instead reset timer and create pulsating effect\n                existingMessage.timer = 0;\n                existingMessage.phase = 'display'; // Reset to display phase\n                existingMessage.animationPhase = 'stable';\n                \n                // Create pulsating effect: scale to 120%, then back to 100%\n                existingMessage.currentScale = 1.0;\n                existingMessage.targetScale = 1.2;\n                existingMessage.pulseTimer = 0;\n                existingMessage.pulsePhase = 'scaleUp'; // scaleUp -> scaleDown\n                existingMessage.pulseDuration = 0.3; // Total pulse duration (0.15s up, 0.15s down)\n                \n                return; // Exit early - don't create new message\n            }\n            \n            // Create new message element\n            const messageElement = document.createElement('div');\n            messageElement.className = 'message' + (isRed ? ' red' : '');\n            messageElement.textContent = text;\n            \n            // Apply custom color if provided\n            if (customColor) {\n                messageElement.style.color = customColor;\n            }\n            \n            // Apply current text size setting\n            const fontSize = window.gameConfig.ui.messageTextSize || 34.2;\n            messageElement.style.fontSize = fontSize + 'px';\n            \n            // Set initial state for animation (invisible, 50% scale, positioned at bottom)\n            messageElement.style.opacity = '0';\n            messageElement.style.transform = 'scale(0.5)';\n            messageElement.style.position = 'absolute';\n            messageElement.style.width = '100%';\n            messageElement.style.transition = 'none'; // No transition initially\n            \n            // Add to queue with detailed animation state\n            const newMessage = {\n                element: messageElement,\n                timer: 0,\n                phase: 'fadeIn', // fadeIn -> display -> fadeOut -> remove\n                displayDuration: 3.5,\n                fadeInDuration: 0.25,\n                fadeOutDuration: 0.25,\n                animationPhase: 'scaleUp', // scaleUp -> settle -> stable\n                targetY: 0, // Will be calculated\n                currentY: 0,\n                targetOpacity: 1,\n                currentOpacity: 0,\n                targetScale: 1,\n                currentScale: 0.5,\n                pulseTimer: 0, // For pulsating effect\n                pulsePhase: null, // null, 'scaleUp', 'scaleDown'\n                pulseDuration: 0.3\n            };\n            \n            // Shift existing messages up and update their target positions\n            messageQueue.forEach((msg, index) => {\n                const messageGap = window.gameConfig.ui.messageGap || 52; // Default 2x the original 26px\n                msg.targetY = (index + 1) * messageGap;\n                \n                // Update opacity based on new position\n                if (index === 0) {\n                    msg.targetOpacity = 0.5; // First message becomes second (50% alpha)\n                } else if (index === 1) {\n                    msg.targetOpacity = 0.2; // Second message becomes third (20% alpha)\n                } else {\n                    msg.targetOpacity = 0; // Hide older messages\n                }\n            });\n            \n            // Add new message to front of queue\n            messageQueue.unshift(newMessage);\n            \n            // Add to DOM\n            messageContainer.appendChild(messageElement);\n            \n            // Start animation on next frame\n            requestAnimationFrame(() => {\n                // Enable transitions for smooth movement\n                messageQueue.forEach(msg => {\n                    msg.element.style.transition = 'opacity 0.25s ease-out, transform 0.25s ease-out';\n                });\n                \n                // Trigger initial fade-in and scale animation for new message\n                newMessage.element.style.opacity = '0';\n                newMessage.element.style.transform = 'translateY(0px) scale(0.5)';\n            });\n        }\n        \n        function updateMessages(deltaTime) {\n            messageQueue = messageQueue.filter((msg, index) => {\n                msg.timer += deltaTime;\n                \n                // Update target position and opacity based on queue position\n                const messageGap = window.gameConfig.ui.messageGap || 52; // Default 2x the original 26px\n                msg.targetY = index * messageGap;\n                \n                if (index === 0) {\n                    msg.targetOpacity = 1; // First message (newest)\n                } else if (index === 1) {\n                    msg.targetOpacity = 0.5; // Second message\n                } else if (index === 2) {\n                    msg.targetOpacity = 0.2; // Third message\n                } else {\n                    msg.targetOpacity = 0; // Hide older messages\n                }\n                \n                // Handle pulsating effect for duplicate messages\n                if (msg.pulsePhase) {\n                    msg.pulseTimer += deltaTime;\n                    \n                    if (msg.pulsePhase === 'scaleUp') {\n                        // Scale from 100% to 120% over 0.15 seconds\n                        const progress = Math.min(msg.pulseTimer / (msg.pulseDuration * 0.5), 1);\n                        msg.currentScale = 1.0 + (0.2 * progress); // 1.0 to 1.2\n                        \n                        if (msg.pulseTimer >= msg.pulseDuration * 0.5) {\n                            msg.pulsePhase = 'scaleDown';\n                        }\n                    } else if (msg.pulsePhase === 'scaleDown') {\n                        // Scale from 120% to 100% over 0.15 seconds\n                        const progress = Math.min((msg.pulseTimer - msg.pulseDuration * 0.5) / (msg.pulseDuration * 0.5), 1);\n                        msg.currentScale = 1.2 - (0.2 * progress); // 1.2 to 1.0\n                        \n                        if (msg.pulseTimer >= msg.pulseDuration) {\n                            // Pulse complete - return to normal state\n                            msg.pulsePhase = null;\n                            msg.pulseTimer = 0;\n                            msg.currentScale = 1.0;\n                        }\n                    }\n                }\n                \n                // Handle different animation phases (only if not pulsing)\n                if (!msg.pulsePhase) {\n                    if (msg.phase === 'fadeIn') {\n                        if (msg.animationPhase === 'scaleUp') {\n                            // First part: scale from 50% to 120% while fading in (0 to 0.1s)\n                            const scaleProgress = Math.min(msg.timer / 0.1, 1);\n                            msg.currentScale = 0.5 + (0.7 * scaleProgress); // 0.5 to 1.2\n                            msg.currentOpacity = scaleProgress; // 0 to 1\n                            \n                            if (msg.timer >= 0.1) {\n                                msg.animationPhase = 'settle';\n                            }\n                        } else if (msg.animationPhase === 'settle') {\n                            // Second part: scale from 120% to 100% (0.1s to 0.25s)\n                            const settleProgress = Math.min((msg.timer - 0.1) / 0.15, 1);\n                            msg.currentScale = 1.2 - (0.2 * settleProgress); // 1.2 to 1.0\n                            msg.currentOpacity = 1; // Stay at full opacity\n                            \n                            if (msg.timer >= msg.fadeInDuration) {\n                                msg.phase = 'display';\n                                msg.timer = 0;\n                                msg.animationPhase = 'stable';\n                                msg.currentScale = 1.0;\n                            }\n                        }\n                    } else if (msg.phase === 'display') {\n                        // Display phase: maintain stable appearance\n                        msg.currentScale = 1.0;\n                        \n                        if (msg.timer >= msg.displayDuration) {\n                            msg.phase = 'fadeOut';\n                            msg.timer = 0;\n                        }\n                    } else if (msg.phase === 'fadeOut') {\n                        // Fade out phase: smooth opacity reduction\n                        const fadeProgress = Math.min(msg.timer / msg.fadeOutDuration, 1);\n                        msg.currentOpacity = msg.targetOpacity * (1 - fadeProgress);\n                        \n                        if (msg.timer >= msg.fadeOutDuration) {\n                            // Remove from DOM and queue\n                            if (msg.element.parentNode) {\n                                msg.element.parentNode.removeChild(msg.element);\n                            }\n                            return false; // Remove from queue\n                        }\n                    }\n                }\n                \n                // Smooth interpolation for position (for sliding when new messages appear)\n                const positionLerpSpeed = 8; // How fast messages slide to new positions\n                msg.currentY += (msg.targetY - msg.currentY) * positionLerpSpeed * deltaTime;\n                \n                // Smooth interpolation for opacity (when messages get pushed down)\n                if (msg.phase !== 'fadeIn' && msg.phase !== 'fadeOut') {\n                    const opacityLerpSpeed = 6;\n                    msg.currentOpacity += (msg.targetOpacity - msg.currentOpacity) * opacityLerpSpeed * deltaTime;\n                }\n                \n                // Apply the calculated values to the DOM element\n                msg.element.style.opacity = msg.currentOpacity.toString();\n                msg.element.style.transform = `translateY(${msg.currentY}px) scale(${msg.currentScale})`;\n                \n                return true; // Keep in queue\n            });\n        }\n        \n        // Seeded random number generator\n        function seededRandom(seed) {\n            const x = Math.sin(seed) * 10000;\n            return x - Math.floor(x);\n        }\n        \n        function generateTreesInGrid(gridX, gridY) {\n            const gridKey = `${gridX},${gridY}`;\n            if (trees.has(gridKey)) return;\n            \n            const treesInGrid = [];\n            const density = window.gameConfig.world.treeDensity;\n            const seed = window.gameConfig.world.seed;\n            \n            // Generate 1.5-3 trees per grid cell based on density (1.5x more dense)\n            const numTrees = Math.floor(1.5 + seededRandom(seed + gridX * 1000 + gridY) * 1.5 * density);\n            \n            for (let i = 0; i < numTrees; i++) {\n                const localSeed = seed + gridX * 10000 + gridY * 100 + i;\n                const x = gridX * GRID_SIZE + seededRandom(localSeed) * GRID_SIZE;\n                const y = gridY * GRID_SIZE + seededRandom(localSeed + 1) * GRID_SIZE;\n                \n                // Don't place trees within central 300px radius around campfire (reduced from 500px)\n                if (Math.sqrt(x * x + y * y) < 300) {\n                    continue;\n                }\n                \n                const treeType = TREE_TYPES[Math.floor(seededRandom(localSeed + 2) * TREE_TYPES.length)];\n                \n                treesInGrid.push({ \n                    x, y, type: treeType, \n                    size: 320 + seededRandom(localSeed + 3) * 160,\n                    health: 10, // Each tree can withstand 10 hits\n                    maxHealth: 10,\n                    shakeTimer: 0,\n                    shakeIntensity: 0,\n                    healthBarTimer: 0, // Timer for health bar visibility\n                    particles: [] // Store particles for this tree\n                });\n            }\n            \n            trees.set(gridKey, treesInGrid);\n        }\n        \n        function generateRocksAndFlowersInGrid(gridX, gridY) {\n            const gridKey = `${gridX},${gridY}`;\n            if (rocksAndFlowers.has(gridKey)) return;\n            \n            const objectsInGrid = [];\n            const seed = window.gameConfig.world.seed;\n            \n            // Generate 1.5-4.5 rocks/flowers per grid cell (1.5x more dense)\n            const numObjects = Math.floor(1.5 + seededRandom(seed + gridX * 2000 + gridY + 500) * 3);\n            \n            for (let i = 0; i < numObjects; i++) {\n                const localSeed = seed + gridX * 20000 + gridY * 200 + i + 1000;\n                const x = gridX * GRID_SIZE + seededRandom(localSeed) * GRID_SIZE;\n                const y = gridY * GRID_SIZE + seededRandom(localSeed + 1) * GRID_SIZE;\n                \n                // Don't place within central 300px radius around campfire\n                if (Math.sqrt(x * x + y * y) < 300) {\n                    continue;\n                }\n                \n                const objectType = ROCK_FLOWER_TYPES[Math.floor(seededRandom(localSeed + 2) * ROCK_FLOWER_TYPES.length)];\n                \n                objectsInGrid.push({ \n                    x, y, type: objectType, \n                    size: objectType === 'minecraft_rock' ? \n                        (80 + seededRandom(localSeed + 3) * 60) : // Rocks: 80-140px\n                        (60 + seededRandom(localSeed + 3) * 40),   // Flowers: 60-100px\n                    health: objectType === 'minecraft_rock' ? 20 : 1, // Rocks: 20 HP, Flowers: 1 HP\n                    maxHealth: objectType === 'minecraft_rock' ? 20 : 1,\n                    shakeTimer: 0,\n                    shakeIntensity: 0,\n                    healthBarTimer: 0,\n                    particles: []\n                });\n            }\n            \n            rocksAndFlowers.set(gridKey, objectsInGrid);\n        }\n        \n        function getVisibleTrees() {\n            const viewportPadding = 200;\n            const minGridX = Math.floor((camera.x - viewportPadding) / GRID_SIZE);\n            const maxGridX = Math.floor((camera.x + canvas.width + viewportPadding) / GRID_SIZE);\n            const minGridY = Math.floor((camera.y - viewportPadding) / GRID_SIZE);\n            const maxGridY = Math.floor((camera.y + canvas.height + viewportPadding) / GRID_SIZE);\n            \n            const visibleTrees = [];\n            \n            for (let gridX = minGridX; gridX <= maxGridX; gridX++) {\n                for (let gridY = minGridY; gridY <= maxGridY; gridY++) {\n                    generateTreesInGrid(gridX, gridY);\n                    const gridTrees = trees.get(`${gridX},${gridY}`) || [];\n                    visibleTrees.push(...gridTrees);\n                }\n            }\n            \n            return visibleTrees;\n        }\n        \n        function getVisibleRocksAndFlowers() {\n            const viewportPadding = 200;\n            const minGridX = Math.floor((camera.x - viewportPadding) / GRID_SIZE);\n            const maxGridX = Math.floor((camera.x + canvas.width + viewportPadding) / GRID_SIZE);\n            const minGridY = Math.floor((camera.y - viewportPadding) / GRID_SIZE);\n            const maxGridY = Math.floor((camera.y + canvas.height + viewportPadding) / GRID_SIZE);\n            \n            const visibleObjects = [];\n            \n            for (let gridX = minGridX; gridX <= maxGridX; gridX++) {\n                for (let gridY = minGridY; gridY <= maxGridY; gridY++) {\n                    generateRocksAndFlowersInGrid(gridX, gridY);\n                    const gridObjects = rocksAndFlowers.get(`${gridX},${gridY}`) || [];\n                    visibleObjects.push(...gridObjects);\n                }\n            }\n            \n            return visibleObjects;\n        }\n        \n        function drawShadow(x, y, size, scale = 1, color = 'black') {\n            const shadowWidth = size * 0.8 * scale;\n            const shadowHeight = shadowWidth * 0.5; // 50% less tall for more oval shape\n            \n            // Create oval gradient\n            ctx.save();\n            ctx.translate(x, y);\n            ctx.scale(1, 0.5); // Squish vertically to 50% height\n            \n            const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, shadowWidth / 2);\n            \n            if (color === 'yellow') {\n                gradient.addColorStop(0, 'rgba(255, 255, 0, 0.65)');\n                gradient.addColorStop(1, 'rgba(255, 255, 0, 0)');\n            } else {\n                gradient.addColorStop(0, 'rgba(0, 0, 0, 0.65)');\n                gradient.addColorStop(1, 'rgba(0, 0, 0, 0)');\n            }\n            \n            ctx.fillStyle = gradient;\n            ctx.beginPath();\n            ctx.arc(0, 0, shadowWidth / 2, 0, Math.PI * 2);\n            ctx.fill();\n            ctx.restore();\n        }\n        \n        function drawAsset(assetId, x, y, size, flipHorizontal = false) {\n            const asset = assetCache[assetId];\n            if (!asset || !asset.complete) return;\n            \n            const drawX = x - size / 2;\n            const drawY = y - size / 2;\n            \n            if (flipHorizontal) {\n                ctx.save();\n                ctx.scale(-1, 1);\n                ctx.drawImage(asset, -drawX - size, drawY, size, size);\n                ctx.restore();\n            } else {\n                ctx.drawImage(asset, drawX, drawY, size, size);\n            }\n        }\n        \n        function drawAxe(x, y, size, facingRight) {\n            // Use current weapon selection\n            let weaponAssetId = getAxeAssetId(axeLevel);\n            if (currentWeapon === 'spear' && hasSpear) {\n                // Use correct spear asset based on level\n                weaponAssetId = getSpearAssetId(spearLevel);\n                \n                // No fallback needed - minecraft_poison_spear is the only poison spear asset\n            }\n            \n            const asset = assetCache[weaponAssetId];\n            if (!asset || !asset.complete) return;\n            \n            // Position weapon 10px further from player\n            const weaponOffsetX = facingRight ? (size * 0.5 + 10) : -(size * 0.5 + 10);\n            const weaponOffsetY = axe.yOffset; // Apply downward translation during swing\n            \n            const weaponX = x + weaponOffsetX;\n            const weaponY = y + weaponOffsetY;\n            const weaponSize = 75;\n            \n            // Draw weapon with rotation about its center\n            ctx.save();\n            ctx.translate(weaponX, weaponY);\n            ctx.rotate(axe.rotation);\n            \n            // Draw the weapon centered at the rotation point\n            const drawX = -weaponSize / 2;\n            const drawY = -weaponSize / 2;\n            \n            if (!facingRight) {\n                ctx.scale(-1, 1);\n            }\n            \n            ctx.drawImage(asset, drawX, drawY, weaponSize, weaponSize);\n            ctx.restore();\n        }\n        \n        function drawTreeHealthBar(x, y, health, maxHealth) {\n            const barWidth = 60;\n            const barHeight = 8;\n            const healthPercent = health / maxHealth;\n            \n            // Background (red)\n            ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';\n            ctx.fillRect(x - barWidth/2, y, barWidth, barHeight);\n            \n            // Health (green)\n            ctx.fillStyle = 'rgba(0, 255, 0, 0.8)';\n            ctx.fillRect(x - barWidth/2, y, barWidth * healthPercent, barHeight);\n            \n            // Border\n            ctx.strokeStyle = 'rgba(0, 0, 0, 0.8)';\n            ctx.lineWidth = 1;\n            ctx.strokeRect(x - barWidth/2, y, barWidth, barHeight);\n        }\n        \n        function drawCampfireIndicator() {\n            // Check if campfire is on screen\n            const campfireScreenX = campfire.x - camera.x;\n            const campfireScreenY = campfire.y - camera.y;\n            const campfireSize = 160;\n            const margin = 100; // Extra margin to ensure campfire is well within view\n            \n            // Check if campfire is visible on screen\n            const isOnScreen = campfireScreenX > -margin && \n                              campfireScreenX < canvas.width + margin &&\n                              campfireScreenY > -margin && \n                              campfireScreenY < canvas.height + margin;\n            \n            if (isOnScreen) {\n                return; // Don't show indicator if campfire is visible\n            }\n            \n            // Calculate direction to campfire\n            const dx = campfire.x - player.x;\n            const dy = campfire.y - player.y;\n            const angle = Math.atan2(dy, dx);\n            \n            // Calculate position on screen edge\n            const edgeMargin = 40; // Distance from edge\n            const centerX = canvas.width / 2;\n            const centerY = canvas.height / 2;\n            \n            // Find intersection point with screen edge\n            let indicatorX, indicatorY;\n            \n            // Calculate the point on the edge of a rectangle\n            const cos = Math.cos(angle);\n            const sin = Math.sin(angle);\n            const abscos = Math.abs(cos);\n            const abssin = Math.abs(sin);\n            \n            const halfWidth = (canvas.width / 2) - edgeMargin;\n            const halfHeight = (canvas.height / 2) - edgeMargin;\n            \n            if (halfWidth * abssin <= halfHeight * abscos) {\n                // Intersects left or right edge\n                indicatorX = cos > 0 ? canvas.width - edgeMargin : edgeMargin;\n                // Fixed: Use correct sign for Y calculation on vertical edges\n                indicatorY = centerY + halfWidth * sin / abscos;\n            } else {\n                // Intersects top or bottom edge\n                // Fixed: Use correct sign for X calculation on horizontal edges\n                indicatorX = centerX + halfHeight * cos / abssin;\n                indicatorY = sin > 0 ? canvas.height - edgeMargin : edgeMargin;\n            }\n            \n            // Draw fire emoji indicator\n            ctx.save();\n            ctx.font = '30px sans-serif';\n            ctx.textAlign = 'center';\n            ctx.textBaseline = 'middle';\n            \n            // Add pulsing glow effect\n            const pulse = Math.sin(Date.now() * 0.003) * 0.2 + 0.8;\n            ctx.shadowColor = 'rgba(255, 100, 0, ' + pulse + ')';\n            ctx.shadowBlur = 20;\n            \n            // Draw background circle\n            ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';\n            ctx.beginPath();\n            ctx.arc(indicatorX, indicatorY, 25, 0, Math.PI * 2);\n            ctx.fill();\n            \n            // Draw the campfire emoji\n            ctx.fillText('\ud83d\udd25', indicatorX, indicatorY);\n            \n            // Calculate and draw distance to campfire\n            const distance = Math.sqrt(dx * dx + dy * dy);\n            const distanceText = (distance / 100).toFixed(1) + 'm';\n            \n            // Draw distance number below the fire emoji\n            ctx.font = '16px sans-serif';\n            ctx.fillStyle = 'white';\n            ctx.strokeStyle = 'black';\n            ctx.lineWidth = 2;\n            ctx.strokeText(distanceText, indicatorX, indicatorY + 35);\n            ctx.fillText(distanceText, indicatorX, indicatorY + 35);\n            \n            ctx.restore();\n        }\n        \n        function drawHelpBubble() {\n            if (!helpBubbleVisible) return;\n            \n            // Find nearest un-rescued child\n            let nearestChild = null;\n            let nearestDistance = Infinity;\n            \n            children.forEach(child => {\n                // Only consider visible, un-rescued children\n                if (child.isVisible !== false && !child.isFollowing) {\n                    const dx = child.x - player.x;\n                    const dy = child.y - player.y;\n                    const distance = Math.sqrt(dx * dx + dy * dy);\n                    \n                    if (distance < nearestDistance && distance <= HELP_BUBBLE_RANGE) {\n                        nearestChild = child;\n                        nearestDistance = distance;\n                    }\n                }\n            });\n            \n            if (!nearestChild) return;\n            \n            // Check if child is on screen\n            const childScreenX = nearestChild.x - camera.x;\n            const childScreenY = nearestChild.y - camera.y;\n            const margin = 50;\n            \n            const isOnScreen = childScreenX > margin && \n                              childScreenX < canvas.width - margin &&\n                              childScreenY > margin && \n                              childScreenY < canvas.height - margin;\n            \n            let bubbleX, bubbleY;\n            \n            if (isOnScreen) {\n                // Track to child position if on screen\n                bubbleX = childScreenX;\n                bubbleY = childScreenY - nearestChild.size/2 - 40; // Position above child\n            } else {\n                // Show at screen edge like campfire indicator\n                const dx = nearestChild.x - player.x;\n                const dy = nearestChild.y - player.y;\n                const angle = Math.atan2(dy, dx);\n                \n                // Calculate position on screen edge\n                const edgeMargin = 60; // Distance from edge\n                const centerX = canvas.width / 2;\n                const centerY = canvas.height / 2;\n                \n                // Find intersection point with screen edge\n                const cos = Math.cos(angle);\n                const sin = Math.sin(angle);\n                const abscos = Math.abs(cos);\n                const abssin = Math.abs(sin);\n                \n                const halfWidth = (canvas.width / 2) - edgeMargin;\n                const halfHeight = (canvas.height / 2) - edgeMargin;\n                \n                if (halfWidth * abssin <= halfHeight * abscos) {\n                    // Intersects left or right edge\n                    bubbleX = cos > 0 ? canvas.width - edgeMargin : edgeMargin;\n                    bubbleY = centerY + halfWidth * sin / abscos;\n                } else {\n                    // Intersects top or bottom edge\n                    bubbleX = centerX + halfHeight * cos / abssin;\n                    bubbleY = sin > 0 ? canvas.height - edgeMargin : edgeMargin;\n                }\n            }\n            \n            // Draw speech bubble\n            ctx.save();\n            \n            // Bubble dimensions\n            const bubbleWidth = 60;\n            const bubbleHeight = 30;\n            const bubbleRadius = 15;\n            const tailSize = 10;\n            \n            // Draw bubble shadow\n            ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';\n            ctx.shadowBlur = 5;\n            ctx.shadowOffsetY = 2;\n            \n            // Draw rounded rectangle bubble\n            ctx.fillStyle = 'white';\n            ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';\n            ctx.lineWidth = 2;\n            \n            ctx.beginPath();\n            ctx.moveTo(bubbleX - bubbleWidth/2 + bubbleRadius, bubbleY - bubbleHeight/2);\n            ctx.lineTo(bubbleX + bubbleWidth/2 - bubbleRadius, bubbleY - bubbleHeight/2);\n            ctx.quadraticCurveTo(bubbleX + bubbleWidth/2, bubbleY - bubbleHeight/2, \n                                  bubbleX + bubbleWidth/2, bubbleY - bubbleHeight/2 + bubbleRadius);\n            ctx.lineTo(bubbleX + bubbleWidth/2, bubbleY + bubbleHeight/2 - bubbleRadius);\n            ctx.quadraticCurveTo(bubbleX + bubbleWidth/2, bubbleY + bubbleHeight/2,\n                                  bubbleX + bubbleWidth/2 - bubbleRadius, bubbleY + bubbleHeight/2);\n            \n            // Add tail if on screen\n            if (isOnScreen) {\n                ctx.lineTo(bubbleX + tailSize, bubbleY + bubbleHeight/2);\n                ctx.lineTo(bubbleX, bubbleY + bubbleHeight/2 + tailSize);\n                ctx.lineTo(bubbleX - tailSize, bubbleY + bubbleHeight/2);\n            }\n            \n            ctx.lineTo(bubbleX - bubbleWidth/2 + bubbleRadius, bubbleY + bubbleHeight/2);\n            ctx.quadraticCurveTo(bubbleX - bubbleWidth/2, bubbleY + bubbleHeight/2,\n                                  bubbleX - bubbleWidth/2, bubbleY + bubbleHeight/2 - bubbleRadius);\n            ctx.lineTo(bubbleX - bubbleWidth/2, bubbleY - bubbleHeight/2 + bubbleRadius);\n            ctx.quadraticCurveTo(bubbleX - bubbleWidth/2, bubbleY - bubbleHeight/2,\n                                  bubbleX - bubbleWidth/2 + bubbleRadius, bubbleY - bubbleHeight/2);\n            ctx.closePath();\n            \n            ctx.fill();\n            ctx.stroke();\n            \n            // Draw \"Help!\" text\n            ctx.fillStyle = 'black';\n            ctx.font = 'bold 16px sans-serif';\n            ctx.textAlign = 'center';\n            ctx.textBaseline = 'middle';\n            ctx.fillText('Help!', bubbleX, bubbleY);\n            \n            ctx.restore();\n        }\n        \n        function drawBackground() {\n            // Use SpongeBob grass if available, fall back to regular grass\n            const grassAsset = assetCache['sb_grass'] && assetCache['sb_grass'].complete ? assetCache['sb_grass'] : assetCache['grass_texture'];\n            if (!grassAsset || !grassAsset.complete) {\n                // Solid fallback so there's never a black gap\n                ctx.fillStyle = '#0a3a5a';\n                ctx.fillRect(0, 0, canvas.width, canvas.height);\n                return;\n            }\n\n            const tw = grassAsset.width  || 512;\n            const th = grassAsset.height || 512;\n\n            // Start one tile before camera offset so edge is always covered\n            const startX = Math.floor(camera.x / tw) * tw - camera.x;\n            const startY = Math.floor(camera.y / th) * th - camera.y;\n\n            for (let x = startX; x < canvas.width + tw; x += tw) {\n                for (let y = startY; y < canvas.height + th; y += th) {\n                    ctx.drawImage(grassAsset, Math.floor(x), Math.floor(y), tw, th);\n                }\n            }\n        }\n        \n        function updatePlayer(deltaTime) {\n            if (gameMode === 'edit') return;\n            \n            // Prevent movement while intro screen is active\n            if (introScreenActive) return;\n            \n            // Handle input\n            let moveX = 0, moveY = 0;\n            \n            if (input.keys['ArrowUp'] || input.keys['KeyW']) moveY -= 1;\n            if (input.keys['ArrowDown'] || input.keys['KeyS']) moveY += 1;\n            if (input.keys['ArrowLeft'] || input.keys['KeyA']) moveX -= 1;\n            if (input.keys['ArrowRight'] || input.keys['KeyD']) moveX += 1;\n            \n            // Virtual joystick input (from Last Stand)\n            if (joystickActive) {\n                // Use joystick input directly for movement\n                moveX = joystickInput.x;\n                moveY = joystickInput.y;\n            }\n            // Mouse input (original 99 nights behavior for desktop)\n            else if (input.mouse.active) {\n                const targetX = input.mouse.x;\n                const targetY = input.mouse.y;\n                \n                player.targetX = targetX + camera.x;\n                player.targetY = targetY + camera.y;\n                \n                const dx = player.targetX - player.x;\n                const dy = player.targetY - player.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                \n                if (distance > 5) {\n                    moveX = dx / distance;\n                    moveY = dy / distance;\n                }\n            }\n            \n            // Normalize diagonal movement for keyboard input only\n            // (joystick and mouse input are already properly normalized)\n            if (!joystickActive && !input.mouse.active && moveX !== 0 && moveY !== 0) {\n                moveX *= 0.707;\n                moveY *= 0.707;\n            }\n            \n            // Apply movement and update facing direction\n            // Reduce speed if hunger is zero, apply skateboard speed bonus if equipped\n            let speedMultiplier = player.hunger <= 0 ? PLAYER_HUNGRY_SPEED_MULTIPLIER : 1.0;\n            if (skateboardEquipped && skateboardLevel > 0) {\n                const skateboardSpeedBonus = SKATEBOARD_SPEED_BONUS[skateboardLevel - 1]; // Convert level 1-3 to index 0-2\n                speedMultiplier *= skateboardSpeedBonus;\n            }\n            player.x += moveX * MOVEMENT_SPEED * speedMultiplier * deltaTime;\n            player.y += moveY * MOVEMENT_SPEED * speedMultiplier * deltaTime;\n            \n            // Calculate current player speed for children to follow\n            const dx = player.x - player.lastX;\n            const dy = player.y - player.lastY;\n            player.currentSpeed = Math.sqrt(dx * dx + dy * dy) / deltaTime;\n            player.lastX = player.x;\n            player.lastY = player.y;\n            \n            // Update facing direction based on horizontal movement\n            if (moveX > 0) {\n                player.facingRight = true;\n            } else if (moveX < 0) {\n                player.facingRight = false;\n            }\n            \n            // Update bounce animation\n            player.isMoving = (moveX !== 0 || moveY !== 0);\n            \n            if (player.isMoving && !skateboardEquipped) {\n                // Rapid bounce while moving (8 bounces per second) - only when not on skateboard\n                player.bounceTimer += deltaTime * 8;\n                player.bounceHeight = Math.abs(Math.sin(player.bounceTimer)) * 20; // 20 pixels max bounce height\n                player.originalBounceHeight = player.bounceHeight;\n            } else {\n                // Reset bounce when not moving or when on skateboard\n                player.bounceTimer = 0;\n                player.bounceHeight = 0;\n                player.originalBounceHeight = 0;\n            }\n            \n            // Update hunger system - lose 5% every 8 seconds (not during intro)\n            // On Day 1, freeze hunger until first tree is chopped\n            if (!introScreenActive && gameSystemsStarted) {\n                player.hungerTimer += deltaTime;\n                if (player.hungerTimer >= 8.0) {\n                    player.hunger = Math.max(0, player.hunger - 5);\n                    player.hungerTimer = 0;\n                    updateHungerBar();\n                }\n            }\n            \n            // Mobile auto-attack: Check for collisions with attackable objects\n            if (joystickActive || input.mouse.active) {\n                checkMobileAutoAttack();\n            }\n            \n            // Check for campfire proximity (200px radius for healing, collision distance for interactions)\n            const campfireDx = player.x - campfire.x;\n            const campfireDy = player.y - campfire.y;\n            const campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy);\n            const campfireCollisionDistance = (player.size + 160) / 2; // 160 is campfire size\n            const campfireHealingDistance = 200; // 200px radius for healing\n            \n            // Healing within 200px radius (5% per second)\n            if (campfireDistance < campfireHealingDistance && player.health < player.maxHealth) {\n                const healAmount = (player.maxHealth * 0.05) * deltaTime; // 5% per second\n                player.health = Math.min(player.maxHealth, player.health + healAmount);\n                updateHealthBar();\n            }\n            \n            // Victory detection: all 4 children rescued and player at campfire\n            if (campfireDistance < campfireHealingDistance && childrenRescued >= 4) {\n                // Check if victory hasn't been triggered yet\n                if (!window.victoryTriggered) {\n                    window.victoryTriggered = true;\n                    showVictoryScreen();\n                }\n            }\n            \n            if (campfireDistance < campfireCollisionDistance) {\n                // Player is touching campfire\n                \n                // Start wood transfer if player has firewood\n                if (firewoodCount > 0 && campfire.fireIntensity < CAMPFIRE_NEARLY_FULL && woodTransfers.length === 0) {\n                    startWoodTransfer();\n                }\n                \n                // If player has raw meat and is hungry, consume only what's needed\n                if (meatCount > 0 && player.hunger < player.maxHunger) {\n                    const hungerDeficit = player.maxHunger - player.hunger;\n                    const meatNeeded = Math.ceil(hungerDeficit / 25); // Each meat restores 25 hunger\n                    const meatToConsume = Math.min(meatNeeded, meatCount);\n                    \n                    for (let i = 0; i < meatToConsume; i++) {\n                        player.hunger = Math.min(player.maxHunger, player.hunger + 25);\n                        meatCount--;\n                    }\n                    \n                    updateMeatInventory();\n                    updateHungerBar();\n                    const _t = TRANSLATIONS[currentLang];\n                    if (meatToConsume === 1) {\n                        showMessage(_t.cookMeat);\n                    } else if (meatToConsume > 1) {\n                        showMessage(_t.ateMultipleMeat(meatToConsume));\n                    }\n                }\n                \n                // If campfire fuel is full and player has meat and isn't too hungry, throw meat for XP\n                const hungerThreshold = player.maxHunger * 0.9; // Similar to CAMPFIRE_NEARLY_FULL\n                if (meatCount > 0 && \n                    campfire.fireIntensity >= CAMPFIRE_NEARLY_FULL && \n                    player.hunger >= hungerThreshold && \n                    woodTransfers.length === 0) {\n                    // Start meat transfer for XP\n                    startMeatTransfer();\n                }\n            }\n        }\n        \n        function updateAxe(deltaTime) {\n            if (axe.isSwinging) {\n                axe.swingTimer += deltaTime;\n                \n                // Calculate rotation progress (0 to 1)\n                const progress = Math.min(axe.swingTimer / axe.swingDuration, 1);\n                \n                // Determine rotation direction based on facing direction\n                const rotationDirection = player.facingRight ? 1 : -1; // CW when facing right, CCW when facing left\n                \n                // Rotate 90 degrees (\u03c0/2 radians) in the appropriate direction\n                axe.rotation = (Math.PI / 2) * progress * rotationDirection;\n                \n                // Smooth downward translation - reaches 40px down at end of swing\n                axe.yOffset = 40 * progress;\n                \n                // End swing when complete\n                if (progress >= 1) {\n                    axe.isSwinging = false;\n                    axe.swingTimer = 0;\n                    axe.rotation = 0; // Reset to original position\n                    axe.yOffset = 0; // Reset to original position\n                    axe.hasHitThisSwing = false; // Reset for next swing\n                }\n            }\n        }\n        \n        function checkAxeCollisions() {\n            if (!axe.isSwinging || axe.hasHitThisSwing) return; // Don't check if already hit something this swing\n            \n            // Cannot attack while skateboard is equipped\n            if (skateboardEquipped) return;\n            \n            const axeOffsetX = player.facingRight ? (player.size * 0.5 + 10) : -(player.size * 0.5 + 10);\n            const axeX = player.x + axeOffsetX;\n            const axeY = player.y;\n            const axeSize = 75;\n            \n            // Check tree collisions\n            const visibleTrees = getVisibleTrees();\n            visibleTrees.forEach(tree => {\n                if (tree.destroyed || tree.fullyDestroyed) return;\n                \n                const dx = axeX - tree.x;\n                const dy = axeY - tree.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const collisionDistance = (axeSize + tree.size) / 2;\n                \n                if (distance < collisionDistance) {\n                    // Hit the tree - calculate damage with weapon and level\n                    let damage = 1;\n                    if (currentWeapon === 'spear' && hasSpear) {\n                        damage = SPEAR_ENVIRONMENT_DAMAGE[getSpearLevelIndex()];\n                    } else {\n                        // Apply axe level multiplier for environment damage\n                        damage = AXE_ENVIRONMENT_DAMAGE[getAxeLevelIndex()];\n                    }\n                    if (player.hunger <= 0) {\n                        damage = Math.ceil(damage * 0.5); // Half damage when hungry\n                    }\n                    tree.health -= damage;\n                    tree.shakeTimer = 0.5;\n                    tree.shakeIntensity = 30; // More intense shake\n                    tree.healthBarTimer = 2.0; // Show health bar for 2 seconds\n                    \n                    // Create particles at axe position\n                    createWoodParticles(axeX, axeY);\n                    playSound('sfx_axe_hit', 0.7);\n                    \n                    // Mark that axe has hit something this swing\n                    axe.hasHitThisSwing = true;\n                    \n                    if (tree.health <= 0) {\n                        // Tree is destroyed\n                        tree.destroyed = true;\n                        tree.destructionTimer = 0;\n                        tree.destructionDuration = 0.8;\n                        tree.destructionScale = 1.0;\n                        tree.originalY = tree.y; // Store original Y for shadow positioning\n\n                        // Spawn firewood piles\n                        spawnFirewoodPiles(tree.x, tree.y);\n\n                        // Hide first tree tutorial arrow\n                        firstTreeArrow.visible = false;\n                    }\n                    \n                    return; // Exit early since we hit something\n                }\n            });\n            \n            // Check rock and flower collisions\n            const visibleRocksAndFlowers = getVisibleRocksAndFlowers();\n            visibleRocksAndFlowers.forEach(obj => {\n                if (obj.destroyed || obj.fullyDestroyed) return;\n                \n                const dx = axeX - obj.x;\n                const dy = axeY - obj.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const collisionDistance = (axeSize + obj.size) / 2;\n                \n                if (distance < collisionDistance) {\n                    // Hit the object - calculate damage with weapon and level\n                    let damage = 1;\n                    if (currentWeapon === 'spear' && hasSpear) {\n                        damage = SPEAR_ENVIRONMENT_DAMAGE[getSpearLevelIndex()];\n                    } else {\n                        // Apply axe level multiplier for environment damage\n                        damage = AXE_ENVIRONMENT_DAMAGE[getAxeLevelIndex()];\n                    }\n                    if (player.hunger <= 0) {\n                        damage = Math.ceil(damage * 0.5); // Half damage when hungry\n                    }\n                    obj.health -= damage;\n                    obj.shakeTimer = 0.5;\n                    obj.shakeIntensity = 30; // More intense shake\n                    obj.healthBarTimer = 2.0; // Show health bar for 2 seconds\n                    \n                    // Create appropriate particles at axe position\n                    playSound('sfx_axe_hit', 0.6);\n                    if (obj.type === 'minecraft_rock') {\n                        createRockParticles(axeX, axeY);\n                    } else if (obj.type === 'minecraft_flower') {\n                        createFlowerParticles(axeX, axeY);\n                    }\n                    \n                    // Mark that axe has hit something this swing\n                    axe.hasHitThisSwing = true;\n                    \n                    if (obj.health <= 0) {\n                        // Object is destroyed\n                        obj.destroyed = true;\n                        obj.destructionTimer = 0;\n                        obj.destructionDuration = 0.8;\n                        obj.destructionScale = 1.0;\n                        obj.originalY = obj.y; // Store original Y for shadow positioning\n                        \n                        // Object destroyed\n                    }\n                    \n                    return; // Exit early since we hit something\n                }\n            });\n        }\n        \n        function createWoodParticles(x, y) {\n            // Create 8-12 voxel particles\n            const numParticles = 8 + Math.floor(Math.random() * 5);\n            \n            for (let i = 0; i < numParticles; i++) {\n                const isGreen = Math.random() > 0.5;\n                \n                // Create 2:1 isometric oval spread\n                const angle = Math.random() * Math.PI * 2;\n                const radius = Math.random() * 60;\n                const radiusX = radius; // Full width\n                const radiusY = radius * 0.5; // Half height for 2:1 ratio\n                \n                // Calculate spawn position\n                const spawnX = x + Math.cos(angle) * radiusX;\n                const spawnY = y + Math.sin(angle) * radiusY;\n                \n                const particle = {\n                    worldX: spawnX, // Store world position\n                    worldY: spawnY,\n                    vx: (Math.random() - 0.5) * 500, // Much faster horizontal velocity\n                    vy: -120 - Math.random() * 200, // Much faster upward velocity\n                    gravity: 400, // Gravity acceleration\n                    life: 1.0,\n                    maxLife: 2.0 + Math.random() * 1.5, // Longer lifespan\n                    size: (9 + Math.random() * 12) * 1.5, // 1.5x bigger random sizes\n                    textureType: isGreen ? 'green' : 'brown', // Use texture instead of color\n                    bounceCount: 0,\n                    maxBounces: 2,\n                    groundY: spawnY + 80 // Each particle lands at its own Y position in the oval\n                };\n                \n                // Add to global particle system\n                if (!window.allParticles) window.allParticles = [];\n                window.allParticles.push(particle);\n            }\n        }\n        \n        function createRockParticles(x, y) {\n            // Create 6-10 grey particles\n            const numParticles = 6 + Math.floor(Math.random() * 5);\n            \n            for (let i = 0; i < numParticles; i++) {\n                // Create 2:1 isometric oval spread\n                const angle = Math.random() * Math.PI * 2;\n                const radius = Math.random() * 60;\n                const radiusX = radius;\n                const radiusY = radius * 0.5; // 2:1 ratio\n                \n                // Calculate spawn position\n                const spawnX = x + Math.cos(angle) * radiusX;\n                const spawnY = y + Math.sin(angle) * radiusY;\n                \n                const particle = {\n                    worldX: spawnX,\n                    worldY: spawnY,\n                    vx: (Math.random() - 0.5) * 500,\n                    vy: -120 - Math.random() * 200,\n                    gravity: 400,\n                    life: 1.0,\n                    maxLife: 2.0 + Math.random() * 1.5,\n                    size: (9 + Math.random() * 12) * 1.5,\n                    textureType: 'grey',\n                    bounceCount: 0,\n                    maxBounces: 2,\n                    groundY: spawnY + 80 // Each particle lands at its own Y position\n                };\n                \n                if (!window.allParticles) window.allParticles = [];\n                window.allParticles.push(particle);\n            }\n        }\n        \n        function createFlowerParticles(x, y) {\n            // Create 4-8 green and red particles\n            const numParticles = 4 + Math.floor(Math.random() * 5);\n            \n            for (let i = 0; i < numParticles; i++) {\n                const isRed = Math.random() > 0.5;\n                // Create 2:1 isometric oval spread\n                const angle = Math.random() * Math.PI * 2;\n                const radius = Math.random() * 60;\n                const radiusX = radius;\n                const radiusY = radius * 0.5; // 2:1 ratio\n                \n                // Calculate spawn position\n                const spawnX = x + Math.cos(angle) * radiusX;\n                const spawnY = y + Math.sin(angle) * radiusY;\n                \n                const particle = {\n                    worldX: spawnX,\n                    worldY: spawnY,\n                    vx: (Math.random() - 0.5) * 500,\n                    vy: -120 - Math.random() * 200,\n                    gravity: 400,\n                    life: 1.0,\n                    maxLife: 2.0 + Math.random() * 1.5,\n                    size: (9 + Math.random() * 12) * 1.5,\n                    textureType: isRed ? 'red' : 'green',\n                    bounceCount: 0,\n                    maxBounces: 2,\n                    groundY: spawnY + 80 // Each particle lands at its own Y position\n                };\n                \n                if (!window.allParticles) window.allParticles = [];\n                window.allParticles.push(particle);\n            }\n        }\n        \n        \n        function spawnFrog() {\n            // Don't spawn frog if asset hasn't loaded yet\n            if (!assetCache['minecraft_frog'] || !assetCache['minecraft_frog'].complete) {\n                return;\n            }\n\n            // Never spawn if there's already one frog on screen\n            const activeFrogs = frogs.filter(frog => !frog.destroyed && !frog.fullyDestroyed);\n            if (activeFrogs.length >= 1) return;\n            \n            // Spawn frog near the player (within visible area)\n            const spawnDistance = 300 + Math.random() * 200; // 300-500px from player\n            const angle = Math.random() * Math.PI * 2;\n            const spawnX = player.x + Math.cos(angle) * spawnDistance;\n            const spawnY = player.y + Math.sin(angle) * spawnDistance;\n            \n            const frog = {\n                x: spawnX,\n                y: spawnY,\n                size: FROG_SIZE_MIN + Math.random() * (FROG_SIZE_MAX - FROG_SIZE_MIN),\n                health: FROG_HEALTH,\n                maxHealth: FROG_HEALTH,\n                bounceTimer: 0,\n                bounceHeight: 0,\n                isMoving: true,\n                movingRight: Math.random() > 0.5, // Random initial direction\n                shakeTimer: 0,\n                shakeIntensity: 0,\n                healthBarTimer: 0,\n                destroyed: false,\n                fullyDestroyed: false,\n                destructionTimer: 0,\n                destructionDuration: 0.8,\n                destructionScale: 1.0,\n                // Random movement behavior\n                moveTimer: 0,\n                moveDirection: Math.random() * Math.PI * 2, // Random initial direction\n                moveSpeed: FROG_SPEED_MIN + Math.random() * (FROG_SPEED_MAX - FROG_SPEED_MIN),\n                directionChangeTimer: 0,\n                directionChangeDuration: 2 + Math.random() * 3 // Change direction every 2-5 seconds\n            };\n            \n            frogs.push(frog);\n        }\n        \n        function spawnDeer() {\n            // Only spawn deer at night\n            if (!isNight) return;\n            \n            // Never spawn if there's already one deer (ensure only 1 deer ever exists)\n            const activeDeer = deer.filter(d => !d.destroyed && !d.fullyDestroyed);\n            if (activeDeer.length >= 1) return;\n            \n            // Calculate direction from campfire to player\n            const dx = player.x - campfire.x;\n            const dy = player.y - campfire.y;\n            const distance = Math.sqrt(dx * dx + dy * dy);\n            \n            // Normalize the direction vector\n            let dirX = 0;\n            let dirY = 0;\n            if (distance > 0) {\n                dirX = dx / distance;\n                dirY = dy / distance;\n            } else {\n                // Fallback to random if player is exactly at campfire\n                const angle = Math.random() * Math.PI * 2;\n                dirX = Math.cos(angle);\n                dirY = Math.sin(angle);\n            }\n            \n            // Spawn deer on opposite side of player from campfire\n            const spawnDistance = 750;\n            const spawnX = player.x + dirX * spawnDistance;\n            const spawnY = player.y + dirY * spawnDistance;\n            \n            // Check if deer should be hungry (every 10th day - day 10, 20, 30, etc.)\n            const isHungry = (window.gameConfig.ui.day % 10 === 0) && (window.gameConfig.ui.day % 100 !== 0);\n            \n            // Check if deer should be demonic (for testing, spawn demonic on first night)\n            const isDemonic = (window.gameConfig.ui.day % 100 === 0); // Temporary: spawn demonic deer on first night for testing\n            \n            const deerEntity = {\n                x: spawnX,\n                y: spawnY,\n                size: 180, // Larger than wolves (150px)\n                health: 8, // More health than wolves (5)\n                maxHealth: 8,\n                bounceTimer: 0,\n                bounceHeight: 0,\n                isMoving: true,\n                movingRight: false,\n                shakeTimer: 0,\n                shakeIntensity: 0,\n                healthBarTimer: 0,\n                destroyed: false,\n                fullyDestroyed: false,\n                destructionTimer: 0,\n                destructionDuration: 0.8,\n                destructionScale: 1.0,\n                // Deer-specific behavior\n                stalking: true, // Deer stalks the player slowly\n                stalkSpeed: DEER_STALK_SPEED,\n                lastPlayerX: player.x,\n                lastPlayerY: player.y,\n                trackingTimer: 0,\n                // Deer states\n                isHungry: isHungry,\n                isDemonic: isDemonic\n            };\n            \n            deer.push(deerEntity);\n            playSound('sfx_deer_growl', 0.85);\n        }\n        \n        \n        \n        function updateFrogs(deltaTime) {\n            if (gameMode === 'edit') return;\n            \n            // Check distance from campfire (deterministic spawning)\n            const campfireDx = player.x - campfire.x;\n            const campfireDy = player.y - campfire.y;\n            const distanceFromCampfire = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy);\n            \n            // Spawn frog deterministically when player is more than 700px from campfire\n            if (distanceFromCampfire > 700) {\n                const activeFrogs = frogs.filter(frog => !frog.destroyed && !frog.fullyDestroyed);\n                // Only spawn if no frogs exist (only one frog at a time)\n                if (activeFrogs.length === 0) {\n                    spawnFrog();\n                }\n            }\n            \n            frogs = frogs.filter(frog => {\n                if (frog.fullyDestroyed) return false;\n                \n                // Update direction change timer\n                frog.directionChangeTimer += deltaTime;\n                if (frog.directionChangeTimer >= frog.directionChangeDuration) {\n                    // Change to random direction\n                    frog.moveDirection = Math.random() * Math.PI * 2;\n                    frog.directionChangeTimer = 0;\n                    frog.directionChangeDuration = 2 + Math.random() * 3; // New random duration\n                }\n                \n                // Move in current direction\n                const moveX = Math.cos(frog.moveDirection);\n                const moveY = Math.sin(frog.moveDirection);\n                \n                frog.x += moveX * frog.moveSpeed * deltaTime;\n                frog.y += moveY * frog.moveSpeed * deltaTime;\n                \n                // Update movement direction for texture flipping\n                frog.movingRight = moveX > 0;\n                \n                // Update bounce animation (same as player and wolves)\n                frog.bounceTimer += deltaTime * 8;\n                frog.bounceHeight = Math.abs(Math.sin(frog.bounceTimer)) * 20;\n                \n                // Update shake animation\n                if (frog.shakeTimer > 0) {\n                    frog.shakeTimer -= deltaTime;\n                    if (frog.shakeTimer <= 0) {\n                        frog.shakeIntensity = 0;\n                    }\n                }\n                \n                // Update health bar timer\n                if (frog.healthBarTimer > 0) {\n                    frog.healthBarTimer -= deltaTime;\n                }\n                \n                // Update destruction animation\n                if (frog.destroyed && frog.destructionTimer !== undefined) {\n                    frog.destructionTimer += deltaTime;\n                    const progress = frog.destructionTimer / frog.destructionDuration;\n                    \n                    if (progress <= 0.5) {\n                        // First half: scale up to 120%\n                        frog.destructionScale = 1 + (progress * 2) * 0.2; // 1.0 to 1.2\n                    } else {\n                        // Second half: scale down to 0%\n                        frog.destructionScale = 1.2 - ((progress - 0.5) * 2) * 1.2; // 1.2 to 0\n                    }\n                    \n                    // Mark for removal when animation is complete\n                    if (progress >= 1) {\n                        frog.fullyDestroyed = true;\n                    }\n                }\n                \n                return true;\n            });\n        }\n        \n        function updateDeer(deltaTime) {\n            if (gameMode === 'edit') return;\n            \n            // Spawn deer on day 1 (for testing demonic deer) and then every 5th day during night (only if no deer exists)\n            if (isNight && (window.gameConfig.ui.day % 5 === 0)) {\n                const activeDeer = deer.filter(d => !d.destroyed && !d.fullyDestroyed);\n                if (activeDeer.length === 0) { // Only spawn if no deer exists\n                    spawnDeer();\n                }\n            }\n            \n            deer = deer.filter(deerEntity => {\n                if (deerEntity.fullyDestroyed) return false;\n                \n                // Handle fleeing behavior (deer running away during middle of day)\n                if (deerEntity.fleeing) {\n                    deerEntity.fleeTimer += deltaTime;\n                    \n                    // Run away from campfire at high speed\n                    const campfireDx = campfire.x - deerEntity.x;\n                    const campfireDy = campfire.y - deerEntity.y;\n                    const campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy);\n                    \n                    if (campfireDistance > 5) {\n                        // Move away from campfire (opposite direction) at high speed\n                        const moveAwayX = -campfireDx / campfireDistance;\n                        const moveAwayY = -campfireDy / campfireDistance;\n                        \n                        // High flee speed\n                        let fleeSpeed = deerEntity.stalkSpeed * DEER_FLEE_SPEED_MULTIPLIER;\n                        \n                        // If deer is hungry, apply speed multiplier\n                        if (deerEntity.isHungry) {\n                            fleeSpeed *= DEER_HUNGRY_SPEED_MULTIPLIER;\n                        }\n                        \n                        // If deer is demonic, apply speed multiplier (on top of hungry bonus if applicable)\n                        if (deerEntity.isDemonic) {\n                            fleeSpeed *= DEER_DEMONIC_SPEED_MULTIPLIER;\n                        }\n                        \n                        deerEntity.x += moveAwayX * fleeSpeed * deltaTime;\n                        deerEntity.y += moveAwayY * fleeSpeed * deltaTime;\n                        \n                        // Update movement direction for texture flipping\n                        deerEntity.movingRight = moveAwayX > 0;\n                    }\n                    \n                    // Check if flee duration is complete - despawn the deer\n                    if (deerEntity.fleeTimer >= deerEntity.fleeDuration) {\n                        deerEntity.fullyDestroyed = true;\n                        return false; // Remove from array\n                    }\n                    \n                    // Continue with normal deer update logic below (bounce, collision, etc.)\n                }\n                // Deer behavior depends on day/night cycle\n                else if (isNight) {\n                    // NIGHT: Deer stalks the player (existing behavior)\n                    if (deerEntity.stalking) {\n                        // Update tracking timer\n                        deerEntity.trackingTimer += deltaTime;\n                        \n                        // Update last known player position every 2 seconds (delayed tracking)\n                        if (deerEntity.trackingTimer >= 2.0) {\n                            deerEntity.lastPlayerX = player.x;\n                            deerEntity.lastPlayerY = player.y;\n                            deerEntity.trackingTimer = 0;\n                        }\n                        \n                        // Check if player is in campfire safe zone\n                        const campfireDx = player.x - campfire.x;\n                        const campfireDy = player.y - campfire.y;\n                        const playerCampfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy);\n                        const campfireSafeZone = 280; // Increased by 40% (200 * 1.4 = 280)\n                        \n                        // Calculate movement toward player\n                        const dx = player.x - deerEntity.x;\n                        const dy = player.y - deerEntity.y;\n                        const distance = Math.sqrt(dx * dx + dy * dy);\n                        \n                        if (distance > 5) {\n                            let moveX = dx / distance;\n                            let moveY = dy / distance;\n                            \n                            // Only apply campfire safe zone logic if deer is NOT demonic\n                            if (!deerEntity.isDemonic) {\n                                // Check if deer would get too close to lit campfire when chasing player\n                                const deerToCampfireDx = deerEntity.x - campfire.x;\n                                const deerToCampfireDy = deerEntity.y - campfire.y;\n                                const deerCampfireDistance = Math.sqrt(deerToCampfireDx * deerToCampfireDx + deerToCampfireDy * deerToCampfireDy);\n                                \n                                // Check if player is in campfire safe zone and fire is lit\n                                const playerInSafeZone = playerCampfireDistance <= campfireSafeZone;\n                                const campfireIsLit = campfire.fireIntensity > 0;\n                                const deerInSafeZone = deerCampfireDistance <= campfireSafeZone;\n                                \n                                // If deer would move into safe zone while player is in safe zone and fire is lit, circle around instead\n                                if (deerInSafeZone && playerInSafeZone && campfireIsLit) {\n                                    // Circle around the safe zone instead of moving toward player\n                                    const angleToCampfire = Math.atan2(deerEntity.y - campfire.y, deerEntity.x - campfire.x);\n                                    const circleAngle = angleToCampfire + Math.PI * 0.5; // 90 degrees offset for circling\n                                    moveX = Math.cos(circleAngle);\n                                    moveY = Math.sin(circleAngle);\n                                }\n                            }\n                            // Demonic deer ignores all campfire logic and moves directly toward player\n                            \n                            // Base speed with night multiplier\n                            let nightSpeed = deerEntity.stalkSpeed * DEER_NIGHT_SPEED_MULTIPLIER;\n                            \n                            // If deer is hungry, apply speed multiplier\n                            if (deerEntity.isHungry) {\n                                nightSpeed *= DEER_HUNGRY_SPEED_MULTIPLIER;\n                            }\n                            \n                            // If deer is demonic, apply speed multiplier (on top of hungry bonus if applicable)\n                            if (deerEntity.isDemonic) {\n                                nightSpeed *= DEER_DEMONIC_SPEED_MULTIPLIER;\n                            }\n                            \n                            deerEntity.x += moveX * nightSpeed * deltaTime;\n                            deerEntity.y += moveY * nightSpeed * deltaTime;\n                            \n                            // Update movement direction for texture flipping\n                            deerEntity.movingRight = moveX > 0;\n                        }\n                    }\n                } else {\n                    // DAYTIME: Deer moves away from campfire\n                    const campfireDx = campfire.x - deerEntity.x;\n                    const campfireDy = campfire.y - deerEntity.y;\n                    const campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy);\n                    \n                    if (campfireDistance > 5) {\n                        // Move away from campfire (opposite direction)\n                        const moveAwayX = -campfireDx / campfireDistance;\n                        const moveAwayY = -campfireDy / campfireDistance;\n                        \n                        // Base speed with day multiplier\n                        let daySpeed = deerEntity.stalkSpeed * DEER_DAY_SPEED_MULTIPLIER;\n                        \n                        // If deer is hungry, apply speed multiplier\n                        if (deerEntity.isHungry) {\n                            daySpeed *= DEER_HUNGRY_SPEED_MULTIPLIER;\n                        }\n                        \n                        // If deer is demonic, apply speed multiplier (on top of hungry bonus if applicable)\n                        if (deerEntity.isDemonic) {\n                            daySpeed *= DEER_DEMONIC_SPEED_MULTIPLIER;\n                        }\n                        \n                        deerEntity.x += moveAwayX * daySpeed * deltaTime;\n                        deerEntity.y += moveAwayY * daySpeed * deltaTime;\n                        \n                        // Update movement direction for texture flipping\n                        deerEntity.movingRight = moveAwayX > 0;\n                    }\n                }\n                \n                // Update bounce animation (slower than wolves for creepy effect)\n                deerEntity.bounceTimer += deltaTime * 6; // Slower bounce\n                deerEntity.bounceHeight = Math.abs(Math.sin(deerEntity.bounceTimer)) * 15; // Less bounce height\n                \n                // Check for player collision and damage\n                const playerDx = player.x - deerEntity.x;\n                const playerDy = player.y - deerEntity.y;\n                const playerDistance = Math.sqrt(playerDx * playerDx + playerDy * playerDy);\n                const playerCollisionDistance = (player.size + deerEntity.size) / 2;\n                \n                if (playerDistance < playerCollisionDistance) {\n                    // Deer deals more damage than wolves (4 damage vs 2.5)\n                    player.health = Math.max(0, player.health - 4);\n                    playSound('sfx_player_hurt', 1.0);\n                    updateHealthBar();\n                    \n                    // Check for death\n                    if (player.health <= 0) {\n                        showGameOverScreen();\n                    }\n                    \n                    // Deer disappears after attacking (one-hit stalker)\n                    deerEntity.destroyed = true;\n                    deerEntity.destructionTimer = 0;\n                    deerEntity.destructionDuration = 0.8;\n                    deerEntity.destructionScale = 1.0;\n                }\n                \n                // Update shake animation\n                if (deerEntity.shakeTimer > 0) {\n                    deerEntity.shakeTimer -= deltaTime;\n                    if (deerEntity.shakeTimer <= 0) {\n                        deerEntity.shakeIntensity = 0;\n                    }\n                }\n                \n                // Update health bar timer\n                if (deerEntity.healthBarTimer > 0) {\n                    deerEntity.healthBarTimer -= deltaTime;\n                }\n                \n                // Update destruction animation\n                if (deerEntity.destroyed && deerEntity.destructionTimer !== undefined) {\n                    deerEntity.destructionTimer += deltaTime;\n                    const progress = deerEntity.destructionTimer / deerEntity.destructionDuration;\n                    \n                    if (progress <= 0.5) {\n                        // First half: scale up to 120%\n                        deerEntity.destructionScale = 1 + (progress * 2) * 0.2; // 1.0 to 1.2\n                    } else {\n                        // Second half: scale down to 0%\n                        deerEntity.destructionScale = 1.2 - ((progress - 0.5) * 2) * 1.2; // 1.2 to 0\n                    }\n                    \n                    // Mark for removal when animation is complete\n                    if (progress >= 1) {\n                        deerEntity.fullyDestroyed = true;\n                    }\n                }\n                \n                return true;\n            });\n        }\n        \n        function updateChildren(deltaTime) {\n            if (gameMode === 'edit') return;\n            \n            // Update help bubble timer\n            helpBubbleTimer += deltaTime;\n            \n            // Check if we have any un-rescued children within range\n            let hasNearbyChild = false;\n            children.forEach(child => {\n                if (child.isVisible !== false && !child.isFollowing) {\n                    const dx = child.x - player.x;\n                    const dy = child.y - player.y;\n                    const distance = Math.sqrt(dx * dx + dy * dy);\n                    if (distance <= HELP_BUBBLE_RANGE) {\n                        hasNearbyChild = true;\n                    }\n                }\n            });\n            \n            // Update help bubble visibility based on timer\n            if (hasNearbyChild) {\n                const cycleTime = HELP_BUBBLE_SHOW_TIME + HELP_BUBBLE_HIDE_TIME;\n                const cyclePosition = helpBubbleTimer % cycleTime;\n                helpBubbleVisible = cyclePosition < HELP_BUBBLE_SHOW_TIME;\n            } else {\n                helpBubbleVisible = false;\n                helpBubbleTimer = 0; // Reset timer when no children nearby\n            }\n            \n            // Check for player touching children to activate following\n            children.forEach(child => {\n                // Only rescue visible children that aren't already following\n                if (!child.isFollowing && child.isVisible !== false) {\n                    const dx = player.x - child.x;\n                    const dy = player.y - child.y;\n                    const distance = Math.sqrt(dx * dx + dy * dy);\n                    const touchDistance = (player.size + child.size) / 2;\n                    \n                    if (distance < touchDistance) {\n                        child.isFollowing = true;\n                        child.followTarget = 'player';\n                        child.rescueOrder = childrenRescued;\n                        childrenRescued++;\n                        bed.childrenRescued = childrenRescued; // Update bed counter\n                    }\n                }\n            });\n            \n            // Set up conga line - based on rescue order, not hard-coded order\n            const followingChildren = children.filter(child => child.isFollowing).sort((a, b) => a.rescueOrder - b.rescueOrder);\n            followingChildren.forEach((child, index) => {\n                if (index === 0) {\n                    child.followTarget = 'player';\n                } else {\n                    child.followTarget = followingChildren[index - 1];\n                }\n            });\n            \n            // Update each child's movement and animation\n            children.forEach(child => {\n                // Skip invisible children completely\n                if (child.isVisible === false) return;\n                \n                if (!child.isFollowing) {\n                    // Stationary children - just handle jumping animation\n                    if (child.isMoving) {\n                        child.jumpTimer += deltaTime * 10;\n                        child.jumpHeight = Math.abs(Math.sin(child.jumpTimer)) * 15;\n                        \n                        // Stop moving when we've reached our target\n                        const dx = child.targetX - child.x;\n                        const dy = child.targetY - child.y;\n                        const distance = Math.sqrt(dx * dx + dy * dy);\n                        \n                        if (distance < 2) {\n                            child.isMoving = false;\n                            child.jumpHeight = 0;\n                            child.speed = 0;\n                        }\n                    } else {\n                        child.jumpHeight = 0;\n                    }\n                    return;\n                }\n                \n                // Following children behavior\n                let targetX, targetY, targetMoving;\n                \n                if (child.followTarget === 'player') {\n                    targetX = player.x;\n                    targetY = player.y;\n                    targetMoving = player.isMoving;\n                } else {\n                    // Following another child\n                    targetX = child.followTarget.x;\n                    targetY = child.followTarget.y;\n                    targetMoving = child.followTarget.isMoving;\n                }\n                \n                // Calculate distance to target\n                const dx = targetX - child.x;\n                const dy = targetY - child.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                \n                // If target is moving and we're far enough, start following\n                if (targetMoving && distance > child.followOffset) {\n                    child.isMoving = true;\n                    child.stopTimer = 0;\n                    \n                    // Match speed with player dynamically (with boost to catch up)\n                    let baseSpeed = Math.max(player.currentSpeed * 1.2, 180); // 20% faster than player, minimum 180\n                    \n                    // Extra boost if child is very far behind\n                    if (distance > child.followOffset * 3) {\n                        baseSpeed *= 1.5; // 50% speed boost when far behind\n                    }\n                    \n                    child.speed = baseSpeed;\n                    \n                    // Move towards target\n                    const moveX = (dx / distance) * child.speed * deltaTime;\n                    const moveY = (dy / distance) * child.speed * deltaTime;\n                    \n                    child.x += moveX;\n                    child.y += moveY;\n                    \n                    // Update direction for sprite flipping\n                    child.movingRight = moveX > 0;\n                    \n                    // Jump animation\n                    child.jumpTimer += deltaTime * 10;\n                    child.jumpHeight = Math.abs(Math.sin(child.jumpTimer)) * 15;\n                } else if (child.isMoving) {\n                    // Target stopped or we're close enough - start stop delay\n                    child.stopTimer += deltaTime;\n                    \n                    if (child.stopTimer >= child.stopDelay) {\n                        // Stop moving after delay\n                        child.isMoving = false;\n                        child.jumpHeight = 0;\n                        child.speed = 0;\n                        child.stopTimer = 0;\n                    } else {\n                        // Continue moving during delay but slower\n                        child.speed *= 0.95; // Gradually slow down\n                        \n                        const moveX = (dx / distance) * child.speed * deltaTime;\n                        const moveY = (dy / distance) * child.speed * deltaTime;\n                        \n                        child.x += moveX;\n                        child.y += moveY;\n                        \n                        // Continue jump animation\n                        child.jumpTimer += deltaTime * 10;\n                        child.jumpHeight = Math.abs(Math.sin(child.jumpTimer)) * 15;\n                    }\n                } else {\n                    child.jumpHeight = 0;\n                }\n            });\n        }\n        \n        function checkMobileAutoAttack() {\n            if (gameMode === 'edit') return;\n            \n            // Cannot attack while skateboard is equipped\n            if (skateboardEquipped) return;\n            \n            // Check for collisions with attackable objects and auto-attack\n            const playerCollisionRadius = player.size / 2;\n            \n            // Check trees\n            const visibleTrees = getVisibleTrees();\n            visibleTrees.forEach(tree => {\n                if (tree.destroyed || tree.fullyDestroyed) return;\n                \n                const dx = player.x - tree.x;\n                const dy = player.y - tree.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const collisionDistance = playerCollisionRadius + (tree.size / 2);\n                \n                if (distance < collisionDistance && !axe.isSwinging) {\n                    // Auto-attack tree\n                    axe.isSwinging = true;\n                    axe.swingTimer = 0;\n                    axe.hasHitThisSwing = false;\n                    return;\n                }\n            });\n            \n            // Check rocks and flowers\n            const visibleRocksAndFlowers = getVisibleRocksAndFlowers();\n            visibleRocksAndFlowers.forEach(obj => {\n                if (obj.destroyed || obj.fullyDestroyed) return;\n                \n                const dx = player.x - obj.x;\n                const dy = player.y - obj.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const collisionDistance = playerCollisionRadius + (obj.size / 2);\n                \n                if (distance < collisionDistance && !axe.isSwinging) {\n                    // Auto-attack object\n                    axe.isSwinging = true;\n                    axe.swingTimer = 0;\n                    axe.hasHitThisSwing = false;\n                    return;\n                }\n            });\n            \n            // Check enemies for auto-attack\n            function checkEnemyAutoAttack(enemyArray, enemyType) {\n                enemyArray.forEach(enemy => {\n                    if (enemy.destroyed || enemy.fullyDestroyed) return;\n                    \n                    const dx = player.x - enemy.x;\n                    const dy = player.y - enemy.y;\n                    const distance = Math.sqrt(dx * dx + dy * dy);\n                    const collisionDistance = playerCollisionRadius + (enemy.size / 2);\n                    \n                    if (distance < collisionDistance && !axe.isSwinging) {\n                        // Auto-attack enemy\n                        axe.isSwinging = true;\n                        axe.swingTimer = 0;\n                        axe.hasHitThisSwing = false;\n                        return;\n                    }\n                });\n            }\n            \n            checkEnemyAutoAttack(wolves, 'wolf');\n            if (!axe.isSwinging) checkEnemyAutoAttack(bears, 'bear');\n            \n            // Check frogs\n            frogs.forEach(frog => {\n                if (frog.destroyed || frog.fullyDestroyed) return;\n                \n                const dx = player.x - frog.x;\n                const dy = player.y - frog.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const collisionDistance = playerCollisionRadius + (frog.size / 2);\n                \n                if (distance < collisionDistance && !axe.isSwinging) {\n                    // Auto-attack frog\n                    axe.isSwinging = true;\n                    axe.swingTimer = 0;\n                    axe.hasHitThisSwing = false;\n                    return;\n                }\n            });\n            \n            // Check deer\n            deer.forEach(deerEntity => {\n                if (deerEntity.destroyed || deerEntity.fullyDestroyed) return;\n                \n                const dx = player.x - deerEntity.x;\n                const dy = player.y - deerEntity.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const collisionDistance = playerCollisionRadius + (deerEntity.size / 2);\n                \n                if (distance < collisionDistance && !axe.isSwinging) {\n                    // Auto-attack deer\n                    axe.isSwinging = true;\n                    axe.swingTimer = 0;\n                    axe.hasHitThisSwing = false;\n                    return;\n                }\n            });\n        }\n        \n        \n        function checkFrogCollisions() {\n            if (!axe.isSwinging || axe.hasHitThisSwing) return;\n            \n            // Cannot attack while skateboard is equipped\n            if (skateboardEquipped) return;\n            \n            const axeOffsetX = player.facingRight ? (player.size * 0.5 + 10) : -(player.size * 0.5 + 10);\n            const axeX = player.x + axeOffsetX;\n            const axeY = player.y;\n            const axeSize = 75;\n            \n            frogs.forEach(frog => {\n                if (frog.destroyed || frog.fullyDestroyed) return;\n                \n                const dx = axeX - frog.x;\n                const dy = axeY - frog.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const collisionDistance = (axeSize + frog.size) / 2;\n                \n                if (distance < collisionDistance) {\n                    // Hit the frog - calculate damage based on weapon and level\n                    let damage = 1;\n                    if (currentWeapon === 'spear' && hasSpear) {\n                        damage = SPEAR_ENEMY_DAMAGE[getSpearLevelIndex()];\n                    } else {\n                        // Apply axe level multiplier for enemy damage\n                        damage = AXE_ENEMY_DAMAGE[getAxeLevelIndex()];\n                    }\n                    if (player.hunger <= 0) {\n                        damage = Math.ceil(damage * 0.5); // Half damage when hungry\n                    }\n                    frog.health -= damage;\n                    frog.shakeTimer = 0.5;\n                    frog.shakeIntensity = 30;\n                    frog.healthBarTimer = 2.0;\n                    \n                    // Create frog particles at axe position\n                    createFrogParticles(axeX, axeY);\n                    \n                    // Mark that axe has hit something this swing\n                    axe.hasHitThisSwing = true;\n                    \n                    if (frog.health <= 0) {\n                        // Frog is destroyed\n                        frog.destroyed = true;\n                        frog.destructionTimer = 0;\n                        frog.destructionDuration = 0.8;\n                        frog.destructionScale = 1.0;\n                        frog.originalY = frog.y;\n                        \n                        \n                        // Frog defeated\n                    }\n                    \n                    return;\n                }\n            });\n        }\n        \n        function checkDeerCollisions() {\n            if (!axe.isSwinging || axe.hasHitThisSwing) return;\n            \n            // Cannot attack while skateboard is equipped\n            if (skateboardEquipped) return;\n            \n            const axeOffsetX = player.facingRight ? (player.size * 0.5 + 10) : -(player.size * 0.5 + 10);\n            const axeX = player.x + axeOffsetX;\n            const axeY = player.y;\n            const axeSize = 75;\n            \n            deer.forEach(deerEntity => {\n                if (deerEntity.destroyed || deerEntity.fullyDestroyed) return;\n                \n                const dx = axeX - deerEntity.x;\n                const dy = axeY - deerEntity.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                const collisionDistance = (axeSize + deerEntity.size) / 2;\n                \n                if (distance < collisionDistance) {\n                    // Hit the deer - calculate damage based on weapon and level\n                    let damage = 1;\n                    if (currentWeapon === 'spear' && hasSpear) {\n                        damage = SPEAR_ENEMY_DAMAGE[getSpearLevelIndex()];\n                    } else {\n                        // Apply axe level multiplier for enemy damage\n                        damage = AXE_ENEMY_DAMAGE[getAxeLevelIndex()];\n                    }\n                    if (player.hunger <= 0) {\n                        damage = Math.ceil(damage * 0.5); // Half damage when hungry\n                    }\n                    deerEntity.health -= damage;\n                    deerEntity.shakeTimer = 0.5;\n                    deerEntity.shakeIntensity = 30;\n                    deerEntity.healthBarTimer = 2.0;\n                    \n                    // Create deer particles at axe position (similar to wolf particles)\n                    createDeerParticles(axeX, axeY);\n                    \n                    // Mark that axe has hit something this swing\n                    axe.hasHitThisSwing = true;\n                    \n                    if (deerEntity.health <= 0) {\n                        // Deer is destroyed\n                        deerEntity.destroyed = true;\n                        deerEntity.destructionTimer = 0;\n                        deerEntity.destructionDuration = 0.8;\n                        deerEntity.destructionScale = 1.0;\n                        deerEntity.originalY = deerEntity.y;\n                        \n                        // Deer defeated\n                    }\n                    \n                    return;\n                }\n            });\n        }\n        \n        function createWolfParticles(x, y) {\n            // Create 6-10 grey and red particles\n            const numParticles = 6 + Math.floor(Math.random() * 5);\n            \n            for (let i = 0; i < numParticles; i++) {\n                const isRed = Math.random() > 0.5;\n                \n                // Create 2:1 isometric oval spread\n                const angle = Math.random() * Math.PI * 2;\n                const radius = Math.random() * 60;\n                const radiusX = radius;\n                const radiusY = radius * 0.5; // 2:1 ratio\n                \n                // Calculate spawn position\n                const spawnX = x + Math.cos(angle) * radiusX;\n                const spawnY = y + Math.sin(angle) * radiusY;\n                \n                const particle = {\n                    worldX: spawnX,\n                    worldY: spawnY,\n                    vx: (Math.random() - 0.5) * 500,\n                    vy: -120 - Math.random() * 200,\n                    gravity: 400,\n                    life: 1.0,\n                    maxLife: 2.0 + Math.random() * 1.5,\n                    size: (9 + Math.random() * 12) * 1.5,\n                    textureType: isRed ? 'red' : 'grey',\n                    bounceCount: 0,\n                    maxBounces: 2,\n                    groundY: spawnY + 80\n                };\n                \n                if (!window.allParticles) window.allParticles = [];\n                window.allParticles.push(particle);\n            }\n        }\n        \n        function createFrogParticles(x, y) {\n            // Create 4-8 green and red particles\n            const numParticles = 4 + Math.floor(Math.random() * 5);\n            \n            for (let i = 0; i < numParticles; i++) {\n                const isRed = Math.random() > 0.5;\n                \n                // Create 2:1 isometric oval spread\n                const angle = Math.random() * Math.PI * 2;\n                const radius = Math.random() * 60;\n                const radiusX = radius;\n                const radiusY = radius * 0.5; // 2:1 ratio\n                \n                // Calculate spawn position\n                const spawnX = x + Math.cos(angle) * radiusX;\n                const spawnY = y + Math.sin(angle) * radiusY;\n                \n                const particle = {\n                    worldX: spawnX,\n                    worldY: spawnY,\n                    vx: (Math.random() - 0.5) * 500,\n                    vy: -120 - Math.random() * 200,\n                    gravity: 400,\n                    life: 1.0,\n                    maxLife: 2.0 + Math.random() * 1.5,\n                    size: (9 + Math.random() * 12) * 1.5,\n                    textureType: isRed ? 'red' : 'green',\n                    bounceCount: 0,\n                    maxBounces: 2,\n                    groundY: spawnY + 80\n                };\n                \n                if (!window.allParticles) window.allParticles = [];\n                window.allParticles.push(particle);\n            }\n        }\n        \n        function createDeerParticles(x, y) {\n            // Create 8-12 black and red particles (more than other enemies)\n            const numParticles = 8 + Math.floor(Math.random() * 5);\n            \n            for (let i = 0; i < numParticles; i++) {\n                const isRed = Math.random() > 0.3; // 70% chance for red (blood), 30% for black\n                \n                // Create 2:1 isometric oval spread\n                const angle = Math.random() * Math.PI * 2;\n                const radius = Math.random() * 70; // Slightly larger spread\n                const radiusX = radius;\n                const radiusY = radius * 0.5; // 2:1 ratio\n                \n                // Calculate spawn position\n                const spawnX = x + Math.cos(angle) * radiusX;\n                const spawnY = y + Math.sin(angle) * radiusY;\n                \n                const particle = {\n                    worldX: spawnX,\n                    worldY: spawnY,\n                    vx: (Math.random() - 0.5) * 600, // Faster particles\n                    vy: -140 - Math.random() * 250, // Higher velocity\n                    gravity: 400,\n                    life: 1.0,\n                    maxLife: 2.5 + Math.random() * 1.5, // Longer lasting\n                    size: (10 + Math.random() * 14) * 1.5, // Slightly larger\n                    textureType: isRed ? 'red' : 'grey', // Use grey for black particles\n                    bounceCount: 0,\n                    maxBounces: 2,\n                    groundY: spawnY + 90\n                };\n                \n                if (!window.allParticles) window.allParticles = [];\n                window.allParticles.push(particle);\n            }\n        }\n        \n        function createCollectionParticles(x, y) {\n            // Create 16-24 small white particles (2x as dense)\n            const numParticles = 16 + Math.floor(Math.random() * 9);\n            \n            for (let i = 0; i < numParticles; i++) {\n                // Create 2:1 isometric oval spread\n                const angle = Math.random() * Math.PI * 2;\n                const radius = Math.random() * 30;\n                const radiusX = radius;\n                const radiusY = radius * 0.5; // 2:1 ratio\n                \n                // Calculate spawn position\n                const spawnX = x + Math.cos(angle) * radiusX;\n                const spawnY = y + Math.sin(angle) * radiusY;\n                \n                const particle = {\n                    worldX: spawnX,\n                    worldY: spawnY,\n                    vx: (Math.random() - 0.5) * 280, // 70% of previous force: 400 * 0.7 = 280\n                    vy: -140 - Math.random() * 280, // 70% of previous force: -200-600 becomes -140-420\n                    gravity: 600, // Increased gravity to make them fall faster\n                    life: 1.0,\n                    maxLife: 1.2 + Math.random() * 0.6, // Slightly longer life to see the fall\n                    baseSize: ((4 + Math.random() * 6) * 2) * 0.75, // 75% of current size: was 8-20, now 6-15\n                    size: 0, // Will be calculated with oscillation\n                    textureType: 'white', // Special white particle type\n                    baseOpacity: 0.6 + Math.random() * 0.4, // Random base opacity between 60% and 100%\n                    opacity: 0, // Will be calculated with oscillation\n                    oscillationTimer: 0, // Timer for oscillation effect\n                    oscillationSpeed: 8 + Math.random() * 4, // Random oscillation speed (8-12 Hz)\n                    bounceCount: 0,\n                    maxBounces: 0, // No bouncing for collection particles\n                    groundY: spawnY + 50 // Each particle lands at its own Y position\n                };\n                \n                if (!window.allParticles) window.allParticles = [];\n                window.allParticles.push(particle);\n            }\n        }\n        \n        function spawnFirewoodPiles(treeX, treeY) {\n            // Ensure first tree drops 3 wood, regular trees drop 2-3\n            const numPiles = !anyTreeChopped ? 3 : 2 + Math.floor(Math.random() * 2);\n            anyTreeChopped = true;\n            \n            for (let i = 0; i < numPiles; i++) {\n                // Random angle for diagonal direction\n                const angle = Math.random() * Math.PI * 2;\n                const distance = (120 + Math.random() * 80) * 1.5; // 1.5x further: 180-300 pixels from tree center\n                \n                // Calculate target position\n                const targetX = treeX + Math.cos(angle) * distance;\n                const targetY = treeY + Math.sin(angle) * distance;\n                \n                // Calculate initial velocity for diagonal movement\n                const speed = 400; // Initial speed\n                const vx = Math.cos(angle) * speed;\n                const vy = Math.sin(angle) * speed;\n                \n                const pile = {\n                    x: treeX, // Start at tree position\n                    y: treeY,\n                    targetX: targetX,\n                    targetY: targetY,\n                    vx: vx,\n                    vy: vy,\n                    initialSpeed: speed,\n                    size: (60 + Math.random() * 20) * 1.5, // 1.5x bigger: 90-120 (was 60-80)\n                    collected: false,\n                    isFlying: true,\n                    flyTimer: 0,\n                    flyDuration: 0.65 // 0.65 seconds flight time\n                };\n                \n                firewoodPiles.push(pile);\n            }\n        }\n        \n        function spawnMeat(wolfX, wolfY) {\n            // Random angle for diagonal direction\n            const angle = Math.random() * Math.PI * 2;\n            const distance = (120 + Math.random() * 80) * 1.5; // 1.5x further: 180-300 pixels from wolf center\n            \n            // Calculate target position\n            const targetX = wolfX + Math.cos(angle) * distance;\n            const targetY = wolfY + Math.sin(angle) * distance;\n            \n            // Calculate initial velocity for diagonal movement\n            const speed = 400; // Initial speed\n            const vx = Math.cos(angle) * speed;\n            const vy = Math.sin(angle) * speed;\n            \n            const meat = {\n                x: wolfX,\n                y: wolfY,\n                targetX: targetX,\n                targetY: targetY,\n                vx: vx,\n                vy: vy,\n                initialSpeed: speed,\n                size: 100 + Math.random() * 40, // 2x bigger: 100-140 (was 50-70)\n                collected: false,\n                isFlying: true,\n                flyTimer: 0,\n                flyDuration: 0.65 // 0.65 seconds flight time\n            };\n            \n            meatPiles.push(meat);\n        }\n        \n        function updateFirewoodPiles(deltaTime) {\n            if (gameMode === 'edit') return;\n            \n            // Update firewood physics and check for player collision\n            firewoodPiles = firewoodPiles.filter(pile => {\n                // Don't immediately remove collected items - let animation play first\n                \n                // Update physics if firewood is still flying\n                if (pile.isFlying) {\n                    pile.flyTimer += deltaTime;\n                    \n                    // Calculate deceleration progress (0 to 1)\n                    const progress = Math.min(pile.flyTimer / pile.flyDuration, 1);\n                    \n                    // Smooth deceleration using easing function (starts fast, slows down smoothly)\n                    const easedProgress = 1 - Math.pow(1 - progress, 3); // Cubic ease-out\n                    \n                    // Calculate current speed (starts at full speed, smoothly decelerates to 0)\n                    const currentSpeedMultiplier = 1 - progress;\n                    pile.vx = Math.cos(Math.atan2(pile.vy, pile.vx)) * pile.initialSpeed * currentSpeedMultiplier;\n                    pile.vy = Math.sin(Math.atan2(pile.vy, pile.vx)) * pile.initialSpeed * currentSpeedMultiplier;\n                    \n                    // Update position\n                    pile.x += pile.vx * deltaTime;\n                    pile.y += pile.vy * deltaTime;\n                    \n                    // Check if flight time is complete\n                    if (pile.flyTimer >= pile.flyDuration) {\n                        pile.isFlying = false;\n                        pile.vx = 0;\n                        pile.vy = 0;\n                    }\n                }\n                \n                // Only check for player collision if firewood has finished flying and not already collected\n                if (!pile.isFlying && !pile.collected) {\n                    const dx = player.x - pile.x;\n                    const dy = player.y - pile.y;\n                    const distance = Math.sqrt(dx * dx + dy * dy);\n                    const collisionDistance = (player.size + pile.size) / 2;\n                    \n                    if (distance < collisionDistance) {\n                        // Collect the firewood with simple scale-down animation\n                        pile.collected = true;\n                        pile.destroyed = true;\n                        pile.destructionTimer = 0;\n                        pile.destructionDuration = 0.3; // Quick animation\n                        pile.destructionScale = 1.0;\n                        \n                        // Spawn white glowing particles at collection point\n                        createCollectionParticles(pile.x, pile.y);\n                        playSound('sfx_collect', 0.6);\n                        \n                        // Show collection message and update inventory immediately\n                        //showMessage(\"Collected +1 Firewood\");\n                        firewoodCount = Math.min(999, firewoodCount + 1);\n                        updateFirewoodInventory();\n                        \n                        // Firewood collected\n\n                        // Show campfire arrow on first wood pickup to guide player\n                        if (!firstWoodPickedUp) {\n                            firstWoodPickedUp = true;\n                            campfireArrow.visible = true;\n                            // Show and start the game timer\n                            const timerEl = document.getElementById('gameTimer');\n                            if (timerEl) timerEl.style.display = 'block';\n                        }\n\n                        // Start game systems if player has collected 10+ wood (even without delivering to campfire)\n                        if (!gameSystemsStarted && firewoodCount >= 10) {\n                            gameSystemsStarted = true;\n                        }\n                        \n                        // Don't return here - let animation code run below\n                    }\n                }\n                \n                // Update collection animation - simple scale down to 0%\n                if (pile.destroyed && pile.destructionTimer !== undefined) {\n                    pile.destructionTimer += deltaTime;\n                    const progress = pile.destructionTimer / pile.destructionDuration;\n                    \n                    // Simple scale down from 100% to 0%\n                    pile.destructionScale = 1.0 - progress;\n                    \n                    // Mark for removal when animation is complete\n                    if (progress >= 1) {\n                        return false; // Remove from array\n                    }\n                }\n                \n                return true; // Keep in array\n            });\n        }\n\n        function updateMeatPiles(deltaTime) {\n            if (gameMode === 'edit') return;\n            \n            // Update meat physics and check for player collision\n            meatPiles = meatPiles.filter(meat => {\n                // Don't immediately remove collected items - let animation play first\n                \n                // Update physics if meat is still flying\n                if (meat.isFlying) {\n                    meat.flyTimer += deltaTime;\n                    \n                    // Calculate deceleration progress (0 to 1)\n                    const progress = Math.min(meat.flyTimer / meat.flyDuration, 1);\n                    \n                    // Smooth deceleration using easing function (starts fast, slows down smoothly)\n                    const easedProgress = 1 - Math.pow(1 - progress, 3); // Cubic ease-out\n                    \n                    // Calculate current speed (starts at full speed, smoothly decelerates to 0)\n                    const currentSpeedMultiplier = 1 - progress;\n                    meat.vx = Math.cos(Math.atan2(meat.vy, meat.vx)) * meat.initialSpeed * currentSpeedMultiplier;\n                    meat.vy = Math.sin(Math.atan2(meat.vy, meat.vx)) * meat.initialSpeed * currentSpeedMultiplier;\n                    \n                    // Update position\n                    meat.x += meat.vx * deltaTime;\n                    meat.y += meat.vy * deltaTime;\n                    \n                    // Check if flight time is complete\n                    if (meat.flyTimer >= meat.flyDuration) {\n                        meat.isFlying = false;\n                        meat.vx = 0;\n                        meat.vy = 0;\n                    }\n                }\n                \n                // Only check for player collision if meat has finished flying and not already collected\n                if (!meat.isFlying && !meat.collected) {\n                    const dx = player.x - meat.x;\n                    const dy = player.y - meat.y;\n                    const distance = Math.sqrt(dx * dx + dy * dy);\n                    const collisionDistance = (player.size + meat.size) / 2;\n                    \n                    if (distance < collisionDistance) {\n                        // Collect the meat with simple scale-down animation\n                        meat.collected = true;\n                        meat.destroyed = true;\n                        meat.destructionTimer = 0;\n                        meat.destructionDuration = 0.3; // Quick animation\n                        meat.destructionScale = 1.0;\n                        \n                        // Spawn white glowing particles at collection point\n                        createCollectionParticles(meat.x, meat.y);\n                        playSound('sfx_collect', 0.5);\n                        \n                        // Show collection message and update inventory immediately\n                        //showMessage(\"Collected +1 Raw Meat\");\n                        meatCount = Math.min(999, meatCount + 1);\n                        updateMeatInventory();\n                        \n                        // Meat collected\n                        \n                        // Don't return here - let animation code run below\n                    }\n                }\n                \n                // Update collection animation - simple scale down to 0%\n                if (meat.destroyed && meat.destructionTimer !== undefined) {\n                    meat.destructionTimer += deltaTime;\n                    const progress = meat.destructionTimer / meat.destructionDuration;\n                    \n                    // Simple scale down from 100% to 0%\n                    meat.destructionScale = 1.0 - progress;\n                    \n                    // Mark for removal when animation is complete\n                    if (progress >= 1) {\n                        return false; // Remove from array\n                    }\n                }\n                \n                return true; // Keep in array\n            });\n        }\n        \n        function updatePoisonSpears(deltaTime) {\n            if (gameMode === 'edit') return;\n            \n            // Deprecated\n        }\n        \n        function updateFirewoodInventory() {\n            // Update the fourth inventory slot with firewood count (Axe, Spear, Skateboard, Wood, Meat)\n            const fourthSlot = document.querySelector('#inventory .inventorySlot:nth-child(4)');\n            if (!fourthSlot) return;\n            \n            // Clear existing content and click handler\n            fourthSlot.innerHTML = '';\n            fourthSlot.onclick = null;\n            fourthSlot.className = 'inventorySlot';\n            \n            if (firewoodCount > 0) {\n                // Add firewood icon\n                const firewoodAsset = lib.getAsset('sb_firewood');\n                if (firewoodAsset) {\n                    const img = document.createElement('img');\n                    img.src = firewoodAsset.url;\n                    img.style.width = '100%';\n                    img.style.height = '100%';\n                    img.style.objectFit = 'contain';\n                    fourthSlot.appendChild(img);\n                    \n                    // Add count text\n                    const countText = document.createElement('div');\n                    countText.textContent = firewoodCount.toString();\n                    countText.style.position = 'absolute';\n                    countText.style.bottom = '2px';\n                    countText.style.right = '4px';\n                    countText.style.color = 'white';\n                    countText.style.fontSize = '25px'; // 2x smaller than Day counter (50px)\n                    countText.style.fontFamily = 'Solitreo, cursive';\n                    countText.style.textShadow = '1px 1px 0 black, -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black';\n                    countText.style.pointerEvents = 'none';\n                    fourthSlot.style.position = 'relative';\n                    fourthSlot.appendChild(countText);\n                }\n            }\n            setSlotLabel(fourthSlot, firewoodCount > 0 ? (currentLang === 'ar' ? '\u062d\u0637\u0628' : 'Firewood') : '');\n            \n            // Update gameConfig to persist firewood count\n            if (!window.gameConfig.inventory) {\n                window.gameConfig.inventory = {};\n            }\n            window.gameConfig.inventory.firewood = firewoodCount;\n        }\n        \n        function updateCraftingArrow(deltaTime) {\n            // Update arrow visibility based on campfire level and craft button usage\n            if (campfire.level >= 2 && !craftingArrow.hidden) {\n                craftingArrow.visible = true;\n                craftingArrow.bobTimer += deltaTime * craftingArrow.bobSpeed;\n            } else {\n                craftingArrow.visible = false;\n            }\n\n            // Update first tree arrow (only visible until first tree is chopped)\n            if (firstTreeArrow.visible && !gameSystemsStarted) {\n                firstTreeArrow.bobTimer += deltaTime * firstTreeArrow.bobSpeed;\n            }\n\n            // Update campfire arrow (visible after first tree chopped, until first wood delivered)\n            if (campfireArrow.visible) {\n                campfireArrow.bobTimer += deltaTime * campfireArrow.bobSpeed;\n            }\n        }\n        \n        function drawTutorialArrow(x, y, sizeMultiplier = 1.0) {\n            // Draw red arrow pointing down with specified size\n            ctx.fillStyle = 'red';\n            ctx.strokeStyle = 'darkred';\n            ctx.lineWidth = 2;\n\n            ctx.beginPath();\n            // Arrow pointing down: triangle shape with size scaling\n            const baseSize = 20; // Base arrow height\n            const baseWidth = 15; // Base arrow width\n            const baseShaft = 5; // Base shaft width\n\n            const height = baseSize * sizeMultiplier;\n            const width = baseWidth * sizeMultiplier;\n            const shaftWidth = baseShaft * sizeMultiplier;\n            const shaftHeight = baseSize * 0.75 * sizeMultiplier; // Shaft is 75% of total height\n\n            ctx.moveTo(x, y + height); // Bottom point\n            ctx.lineTo(x - width, y); // Left point\n            ctx.lineTo(x - shaftWidth, y); // Left of shaft\n            ctx.lineTo(x - shaftWidth, y - shaftHeight); // Top left of shaft\n            ctx.lineTo(x + shaftWidth, y - shaftHeight); // Top right of shaft\n            ctx.lineTo(x + shaftWidth, y); // Right of shaft\n            ctx.lineTo(x + width, y); // Right point\n            ctx.closePath();\n\n            ctx.fill();\n            ctx.stroke();\n        }\n\n        function drawCraftingArrow() {\n            if (!craftingArrow.visible || campfire.level < 2) return;\n\n            // Calculate arrow position (above workstation)\n            const arrowX = workstation.x - camera.x;\n            const arrowY = workstation.y - camera.y - 80; // 80px above workstation\n\n            // Calculate bobbing offset\n            const bobOffset = Math.sin(craftingArrow.bobTimer) * craftingArrow.bobHeight;\n            const finalY = arrowY + bobOffset;\n\n            // Draw arrow using generalized function (normal size)\n            drawTutorialArrow(arrowX, finalY, 1.5);\n        }\n\n        function drawFirstTreeArrow() {\n            if (!firstTreeArrow.visible || gameSystemsStarted) return;\n\n            // Calculate arrow position (above first tree location)\n            const arrowX = FIRST_TREE_ARROW_X - camera.x;\n            const arrowY = FIRST_TREE_ARROW_Y - camera.y - 80; // 80px above tree\n\n            // Calculate bobbing offset\n            const bobOffset = Math.sin(firstTreeArrow.bobTimer) * firstTreeArrow.bobHeight;\n            const finalY = arrowY + bobOffset;\n\n            // Draw arrow using generalized function (80% larger = 1.8x size)\n            drawTutorialArrow(arrowX, finalY, 1.8);\n        }\n\n        function drawCampfireArrow() {\n            if (!campfireArrow.visible) return;\n\n            // Calculate arrow position (above campfire)\n            const arrowX = campfire.x - camera.x;\n            const arrowY = campfire.y - camera.y - 100; // 100px above campfire\n\n            // Calculate bobbing offset\n            const bobOffset = Math.sin(campfireArrow.bobTimer) * campfireArrow.bobHeight;\n            const finalY = arrowY + bobOffset;\n\n            // Draw arrow using generalized function (80% larger = 1.8x size)\n            drawTutorialArrow(arrowX, finalY, 2.5);\n        }\n\n\n        function updateMeatInventory() {\n            // Update the fifth inventory slot with meat count (Axe, Spear, Skateboard, Wood, Meat)\n            const fifthSlot = document.querySelector('#inventory .inventorySlot:nth-child(5)');\n            if (!fifthSlot) return;\n            \n            // Clear existing content and click handler\n            fifthSlot.innerHTML = '';\n            fifthSlot.onclick = null;\n            fifthSlot.className = 'inventorySlot';\n            \n            if (meatCount > 0) {\n                // Add meat icon\n                const meatAsset = lib.getAsset('sb_meat');\n                if (meatAsset) {\n                    const img = document.createElement('img');\n                    img.src = meatAsset.url;\n                    img.style.width = '100%';\n                    img.style.height = '100%';\n                    img.style.objectFit = 'contain';\n                    fifthSlot.appendChild(img);\n                    \n                    // Add count text\n                    const countText = document.createElement('div');\n                    countText.textContent = meatCount.toString();\n                    countText.style.position = 'absolute';\n                    countText.style.bottom = '2px';\n                    countText.style.right = '4px';\n                    countText.style.color = 'white';\n                    countText.style.fontSize = '25px'; // 2x smaller than Day counter (50px)\n                    countText.style.fontFamily = 'Solitreo, cursive';\n                    countText.style.textShadow = '1px 1px 0 black, -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black';\n                    countText.style.pointerEvents = 'none';\n                    fifthSlot.style.position = 'relative';\n                    fifthSlot.appendChild(countText);\n                }\n            }\n            setSlotLabel(fifthSlot, meatCount > 0 ? (currentLang === 'ar' ? '\u0644\u062d\u0645' : 'Meat') : '');\n            \n            // Update gameConfig to persist meat count\n            if (!window.gameConfig.inventory) {\n                window.gameConfig.inventory = {};\n            }\n            window.gameConfig.inventory.meat = meatCount;\n        }\n        \n        // Helper function to add both click and touch handlers to inventory slots\n        function getSlotLabel(slot) {\n            let label = slot.querySelector('.inventorySlotLabel');\n            if (!label) {\n                label = document.createElement('div');\n                label.className = 'inventorySlotLabel';\n                slot.appendChild(label);\n            }\n            return label;\n        }\n\n        function setSlotLabel(slot, text) {\n            const label = getSlotLabel(slot);\n            label.textContent = text || '';\n        }\n\n        function addInventoryHandlers(slot, handler) {\n            if (!slot) return;\n            \n            // Remove old handlers first to prevent stacking\n            slot.onclick = null;\n            // Remove old touch listener if it exists (store reference on element)\n            if (slot._touchHandler) {\n                slot.removeEventListener('touchend', slot._touchHandler);\n            }\n            \n            // Create new touch handler\n            const touchHandler = (e) => {\n                e.stopPropagation(); // Prevent this from bubbling to canvas\n                e.preventDefault();\n                handler();\n            };\n            \n            // Store reference for later removal\n            slot._touchHandler = touchHandler;\n            \n            // Click handler for desktop\n            slot.onclick = handler;\n            \n            // Touch handler for mobile - use touchend to prevent conflicts with joystick\n            slot.addEventListener('touchend', touchHandler, { passive: false });\n        }\n        \n        function updateWeaponInventory() {\n            // Always show axe in first slot\n            const firstSlot = document.querySelector('#inventory .inventorySlot:nth-child(1)');\n            if (firstSlot) {\n                firstSlot.innerHTML = '';\n                firstSlot.className = 'inventorySlot' + (currentWeapon === 'axe' && !skateboardEquipped ? ' selected' : '');\n                \n                const axeAssetId = getAxeAssetId(axeLevel);\n                const axeAsset = lib.getAsset(axeAssetId);\n                if (axeAsset) {\n                    const img = document.createElement('img');\n                    img.src = axeAsset.url;\n                    img.style.width = '100%';\n                    img.style.height = '100%';\n                    img.style.objectFit = 'contain';\n                    img.style.pointerEvents = 'none';\n                    firstSlot.appendChild(img);\n                }\n                \n                // Add both click and touch handlers for axe selection\n                addInventoryHandlers(firstSlot, () => {\n                    if (gameMode === 'play' && (currentWeapon !== 'axe' || skateboardEquipped)) {\n                        currentWeapon = 'axe';\n                        skateboardEquipped = false;\n                        updateWeaponInventory();\n                        updateSkateboardInventory();\n                    }\n                });\n                \n                // Axe label\n                const axeNames = { old: currentLang === 'ar' ? '\u0641\u0623\u0633 \u0642\u062f\u064a\u0645' : 'Old Axe', good: currentLang === 'ar' ? '\u0641\u0623\u0633 \u062c\u064a\u062f' : 'Good Axe', strong: currentLang === 'ar' ? '\u0641\u0623\u0633 \u0642\u0648\u064a' : 'Strong Axe' };\n                setSlotLabel(firstSlot, axeNames[axeLevel] || 'Axe');\n            }\n            \n            // Show spear in second slot if player has it (Axe, Spear, Skateboard, Wood, Meat)\n            const secondSlot = document.querySelector('#inventory .inventorySlot:nth-child(2)');\n            if (secondSlot) {\n                secondSlot.innerHTML = '';\n                // Clear both click and touch handlers\n                secondSlot.onclick = null;\n                if (secondSlot._touchHandler) {\n                    secondSlot.removeEventListener('touchend', secondSlot._touchHandler);\n                    secondSlot._touchHandler = null;\n                }\n                \n                if (hasSpear) {\n                    secondSlot.className = 'inventorySlot' + (currentWeapon === 'spear' && !skateboardEquipped ? ' selected' : '');\n                    \n                    // Get correct spear asset based on level\n                    const spearAssetId = getSpearAssetId(spearLevel);\n                    let spearAsset = lib.getAsset(spearAssetId);\n                    \n                    // No fallback - use only minecraft_poison_spear\n                    \n                    if (spearAsset) {\n                        const img = document.createElement('img');\n                        img.src = spearAsset.url;\n                        img.style.width = '100%';\n                        img.style.height = '100%';\n                        img.style.objectFit = 'contain';\n                        img.style.pointerEvents = 'none';\n                        secondSlot.appendChild(img);\n                    } else {\n                        // Fallback to axe with green tint\n                        const axeAsset = lib.getAsset('minecraft_axe');\n                        if (axeAsset) {\n                            const img = document.createElement('img');\n                            img.src = axeAsset.url;\n                            img.style.width = '100%';\n                            img.style.height = '100%';\n                            img.style.objectFit = 'contain';\n                            img.style.filter = 'hue-rotate(120deg) brightness(1.2)';\n                            img.style.pointerEvents = 'none';\n                            secondSlot.appendChild(img);\n                        }\n                    }\n                    \n                    // Add both click and touch handlers for spear selection\n                    addInventoryHandlers(secondSlot, () => {\n                        if (gameMode === 'play' && (currentWeapon !== 'spear' || skateboardEquipped)) {\n                            currentWeapon = 'spear';\n                            skateboardEquipped = false;\n                            updateWeaponInventory();\n                            updateSkateboardInventory();\n                        }\n                    });\n                    \n                    // Spear label\n                    const spearNames = { 1: currentLang === 'ar' ? '\u0631\u0645\u062d \u0623\u0633\u0627\u0633\u064a' : 'Basic Spear', 2: currentLang === 'ar' ? '\u0631\u0645\u062d \u062d\u0627\u062f' : 'Sharp Spear', 3: currentLang === 'ar' ? '\u0631\u0645\u062d \u0645\u0633\u0645\u0648\u0645' : 'Poison Spear' };\n                    setSlotLabel(secondSlot, spearNames[spearLevel] || (currentLang === 'ar' ? '\u0631\u0645\u062d' : 'Spear'));\n                } else {\n                    secondSlot.className = 'inventorySlot';\n                    setSlotLabel(secondSlot, '');\n                }\n            }\n            \n            // Update gameConfig to persist weapon state\n            if (!window.gameConfig.inventory) {\n                window.gameConfig.inventory = {};\n            }\n            window.gameConfig.inventory.hasSpear = hasSpear;\n            window.gameConfig.inventory.spearLevel = spearLevel;\n            window.gameConfig.inventory.currentWeapon = currentWeapon;\n        }\n        \n        function updateSkateboardInventory() {\n            // Show skateboard in third slot if player has it (Axe, Spear, Skateboard, Wood, Meat)\n            const thirdSlot = document.querySelector('#inventory .inventorySlot:nth-child(3)');\n            if (thirdSlot) {\n                thirdSlot.innerHTML = '';\n                // Clear both click and touch handlers\n                thirdSlot.onclick = null;\n                if (thirdSlot._touchHandler) {\n                    thirdSlot.removeEventListener('touchend', thirdSlot._touchHandler);\n                    thirdSlot._touchHandler = null;\n                }\n                \n                if (hasSkateBoard) {\n                    thirdSlot.className = 'inventorySlot' + (skateboardEquipped ? ' selected' : '');\n                    \n                    const skateboardAssetId = getSkateboardAssetId(skateboardLevel);\n                    const skateboardAsset = lib.getAsset(skateboardAssetId);\n                    if (skateboardAsset) {\n                        const img = document.createElement('img');\n                        img.src = skateboardAsset.url;\n                        img.style.width = '100%';\n                        img.style.height = '100%';\n                        img.style.objectFit = 'contain';\n                        img.style.pointerEvents = 'none';\n                        thirdSlot.appendChild(img);\n                    }\n                    \n                    // Add both click and touch handlers for skateboard selection\n                    addInventoryHandlers(thirdSlot, () => {\n                        if (gameMode === 'play' && !skateboardEquipped) {\n                            skateboardEquipped = true;\n                            // No weapon equipped when skateboard is equipped\n                            updateWeaponInventory();\n                            updateSkateboardInventory();\n                        }\n                    });\n                    \n                    // Skateboard label\n                    const skateNames = { 1: currentLang === 'ar' ? '\u0633\u0643\u064a\u062a \u0628\u0648\u0631\u062f' : 'Skateboard', 2: currentLang === 'ar' ? '\u0644\u0648\u062d \u0633\u0631\u064a\u0639' : 'Fastboard', 3: currentLang === 'ar' ? '\u0644\u0648\u062d \u062e\u0627\u0631\u0642' : 'Superboard' };\n                    setSlotLabel(thirdSlot, skateNames[skateboardLevel] || (currentLang === 'ar' ? '\u0633\u0643\u064a\u062a' : 'Skateboard'));\n                } else {\n                    thirdSlot.className = 'inventorySlot';\n                    setSlotLabel(thirdSlot, '');\n                }\n            }\n            \n            // Update gameConfig to persist skateboard state\n            if (!window.gameConfig.inventory) {\n                window.gameConfig.inventory = {};\n            }\n            window.gameConfig.inventory.hasSkateBoard = hasSkateBoard;\n            window.gameConfig.inventory.skateboardEquipped = skateboardEquipped;\n        }\n        \n        function updateHealthBar() {\n            const healthBarFill = document.getElementById('healthBarFill');\n            if (!healthBarFill) return;\n            \n            const healthPercent = (player.health / player.maxHealth) * 100;\n            healthBarFill.style.width = healthPercent + '%';\n        }\n        \n        function updateHungerBar() {\n            const hungerBarFill = document.getElementById('hungerBarFill');\n            if (!hungerBarFill) return;\n            \n            const hungerPercent = (player.hunger / player.maxHunger) * 100;\n            hungerBarFill.style.width = hungerPercent + '%';\n        }\n        \n        // Player XP system removed - only campfire XP exists\n        \n        function startWoodTransfer() {\n            if (firewoodCount <= 0) return;\n            \n            // Queue ALL available wood at once with staggered delays\n            const woodToTransfer = firewoodCount;\n            firewoodCount = 0;\n            updateFirewoodInventory();\n            \n            for (let i = 0; i < woodToTransfer; i++) {\n                woodTransfers.push({\n                    startX: player.x,\n                    startY: player.y,\n                    targetX: campfire.x,\n                    targetY: campfire.y - 20,\n                    timer: -(i * 0.12), // stagger each piece by 0.12s\n                    duration: 0.5,\n                    size: 90,\n                    currentX: player.x,\n                    currentY: player.y,\n                    currentSize: 90\n                });\n            }\n        }\n        \n        function updateWoodTransfers(deltaTime) {\n            woodTransfers = woodTransfers.filter(transfer => {\n                transfer.timer += deltaTime;\n                // Still waiting for stagger delay\n                if (transfer.timer < 0) {\n                    transfer.currentX = transfer.startX;\n                    transfer.currentY = transfer.startY;\n                    return true;\n                }\n                const progress = Math.min(transfer.timer / transfer.duration, 1);\n                \n                // Arc animation\n                const easedProgress = 1 - Math.pow(1 - progress, 2); // Ease out\n                \n                // Calculate arc position\n                const dx = transfer.targetX - transfer.startX;\n                const dy = transfer.targetY - transfer.startY;\n                \n                transfer.currentX = transfer.startX + dx * easedProgress;\n                transfer.currentY = transfer.startY + dy * easedProgress;\n                \n                // Add arc height (peak at 50% progress)\n                const arcHeight = 130; // Peak height of arc\n                const arcProgress = Math.sin(progress * Math.PI);\n                transfer.currentY -= arcHeight * arcProgress;\n                \n                // Scale during flight\n                transfer.currentSize = transfer.size * (1 - progress * 0.3); // Shrink to 70% at end\n                \n                if (progress >= 1) {\n                    // Transfer complete - credit the campfire\n                    campfire.fireIntensity = Math.min(1.0, campfire.fireIntensity + CAMPFIRE_FUEL_PER_WOOD);\n                    campfire.fireTimer = Math.max(0, campfire.fireTimer - (window.gameConfig.fireDuration || 10) * CAMPFIRE_FUEL_PER_WOOD);\n\n                    // Hide campfire arrow after first wood delivery\n                    if (campfireArrow.visible) {\n                        campfireArrow.visible = false;\n                        showMessage(TRANSLATIONS[currentLang].campfireProtects, false, '#8A2BE2');\n                    }\n\n                    // Gain campfire XP\n                    gainCampfireXP(1);\n                    \n                    // Start game systems when first wood is delivered\n                    gameSystemsStarted = true;\n\n                    // Update fire bar\n                    updateFireBar();\n                    \n                    return false; // Remove this transfer\n                }\n                \n                return true;\n            });\n        }\n        \n        function startMeatTransfer() {\n            if (meatCount <= 0 || meatTransfers.length > 0) return;\n            \n            // Create meat transfer animation\n            const transfer = {\n                startX: player.x,\n                startY: player.y,\n                targetX: campfire.x,\n                targetY: campfire.y - 20, // Slightly above campfire center\n                timer: 0,\n                duration: 0.5, // 0.5 seconds per meat\n                size: 70, // Slightly smaller than wood\n                currentX: player.x,\n                currentY: player.y,\n                currentSize: 70\n            };\n            \n            meatTransfers.push(transfer);\n            \n            // Immediately deduct from inventory\n            meatCount--;\n            updateMeatInventory();\n        }\n        \n        function updateMeatTransfers(deltaTime) {\n            meatTransfers = meatTransfers.filter(transfer => {\n                transfer.timer += deltaTime;\n                const progress = Math.min(transfer.timer / transfer.duration, 1);\n                \n                // Arc animation (same as wood)\n                const easedProgress = 1 - Math.pow(1 - progress, 2); // Ease out\n                \n                // Calculate arc position\n                const dx = transfer.targetX - transfer.startX;\n                const dy = transfer.targetY - transfer.startY;\n                \n                transfer.currentX = transfer.startX + dx * easedProgress;\n                transfer.currentY = transfer.startY + dy * easedProgress;\n                \n                // Add arc height (peak at 50% progress)\n                const arcHeight = 130; // Peak height of arc\n                const arcProgress = Math.sin(progress * Math.PI);\n                transfer.currentY -= arcHeight * arcProgress;\n                \n                // Scale during flight\n                transfer.currentSize = transfer.size * (1 - progress * 0.3); // Shrink to 70% at end\n                \n                if (progress >= 1) {\n                    // Transfer complete - only gain XP (no fuel added)\n                    gainCampfireXP(1);\n                    \n                    // Check if more meat can be thrown\n                    const campfireDx = player.x - campfire.x;\n                    const campfireDy = player.y - campfire.y;\n                    const campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy);\n                    const campfireCollisionDistance = (player.size + 160) / 2;\n                    const hungerThreshold = player.maxHunger * 0.9;\n                    \n                    if (meatCount > 0 && \n                        campfire.fireIntensity >= CAMPFIRE_NEARLY_FULL && \n                        player.hunger >= hungerThreshold && \n                        campfireDistance < campfireCollisionDistance &&\n                        woodTransfers.length === 0) {\n                        // Start next meat transfer\n                        startMeatTransfer();\n                    }\n                    \n                    return false; // Remove this transfer\n                }\n                \n                return true;\n            });\n        }\n        \n        function gainCampfireXP(amount) {\n            // Don't gain XP if at max level\n            if (campfire.level >= 6) return;\n            \n            campfire.xp += amount;\n            \n            // Check for level up\n            if (campfire.xp >= campfire.maxXp && campfire.level < 6) {\n                campfire.level++;\n                campfire.xp = 0;\n\n                // Set new XP threshold based on level (array is 0-indexed)\n                campfire.maxXp = CAMPFIRE_XP_THRESHOLDS[campfire.level - 1];\n\n                // Trigger level up effect\n                campfire.levelUpEffect = true;\n                campfire.levelUpTimer = 0;\n\n                showMessage(TRANSLATIONS[currentLang].campfireLevel(campfire.level));\n                playSound('sfx_levelup', 0.9);\n\n                // Re-enable red arrow at level 4 if it was hidden at level 2\n                if (campfire.level === 4 && craftingArrow.revealAgainAtLevel4) {\n                    craftingArrow.hidden = false;\n                    craftingArrow.revealAgainAtLevel4 = false;\n                    showMessage(TRANSLATIONS[currentLang].newUpgrades);\n                }\n\n                // Enable workstation at level 2\n                if (campfire.level === 2) {\n                    // Particle burst at workstation location\n                    createCollectionParticles(workstation.x, workstation.y);\n                }\n\n                // Enable bed at level 3\n                if (campfire.level === 3) {\n                    // Particle burst at bed location\n                    createCollectionParticles(bed.x, bed.y);\n                }\n\n                // Enable radar at level 5\n                if (campfire.level === 5) {\n                    radar.enabled = true;\n                    showMessage(TRANSLATIONS[currentLang].radarActivated, false, '#00ffff');\n\n                    // Particle burst at radar location\n                    createCollectionParticles(radar.x, radar.y);\n                }\n\n                // Create burst of flames\n                createCampfireLevelUpEffect();\n            }\n            \n            // Always update the XP bar display\n            updateXPBar();\n        }\n        \n        function createCampfireLevelUpEffect() {\n            // Create burst of fire particles\n            for (let i = 0; i < 30; i++) {\n                const angle = (Math.PI * 2 * i) / 30;\n                const speed = 100 + Math.random() * 100;\n                \n                campfire.fireParticles.push({\n                    x: campfire.x,\n                    y: campfire.y,\n                    vx: Math.cos(angle) * speed,\n                    vy: Math.sin(angle) * speed - 100, // Upward bias\n                    life: 1.0,\n                    maxLife: 1.0 + Math.random() * 0.5,\n                    size: 8 + Math.random() * 8,\n                    color: Math.random() > 0.3 ? 'yellow' : 'orange',\n                    waveOffset: 0,\n                    waveSpeed: 0,\n                    isLevelUp: true // Special flag for level up particles\n                });\n            }\n        }\n        \n        function updateFireBar() {\n            const fireBarFill = document.getElementById('fireBarFill');\n            if (!fireBarFill) return;\n            \n            // Check if campfire is initialized\n            if (typeof campfire === 'undefined') return;\n            \n            const firePercent = campfire.fireIntensity * 100;\n            fireBarFill.style.width = firePercent + '%';\n        }\n        \n        function updateXPBar() {\n            const xpBarFill = document.getElementById('xpBarFill');\n            const xpBarLabel = document.getElementById('xpBarLabel');\n            const xpBarBackground = document.getElementById('xpBarBackground');\n            if (!xpBarFill || !xpBarLabel) return;\n            \n            // Check if campfire is at max level\n            const _xt = TRANSLATIONS[currentLang];\n            if (campfire.level >= 6) {\n                xpBarFill.style.width = '0%';\n                if (xpBarBackground) xpBarBackground.style.display = 'none';\n                xpBarLabel.textContent = _xt.maxCampfireLevel;\n            } else {\n                if (xpBarBackground) xpBarBackground.style.display = 'block';\n                const xpPercent = (campfire.xp / campfire.maxXp) * 100;\n                xpBarFill.style.width = xpPercent + '%';\n                xpBarLabel.textContent = _xt.levelProgress(campfire.level, campfire.xp, campfire.maxXp);\n            }\n        }\n        \n        function updateXPBarVisibility() {\n            const xpBar = document.getElementById('xpBar');\n            if (!xpBar) return;\n            \n            // Check if player is within 200px radius of campfire\n            const campfireDx = player.x - campfire.x;\n            const campfireDy = player.y - campfire.y;\n            const campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy);\n            \n            if (campfireDistance < 200) {\n                // Position XP bar centered over campfire, 50px above it\n                const screenX = campfire.x - camera.x;\n                const screenY = campfire.y - camera.y - 50;\n                \n                // Center the 300px wide bar over the campfire\n                xpBar.style.left = (screenX - 150) + 'px';\n                xpBar.style.top = screenY + 'px';\n                xpBar.style.opacity = '1';\n            } else {\n                xpBar.style.opacity = '0';\n            }\n        }\n        \n        function upgradeAxe(level) {\n            // Check if player has enough wood\n            const costs = { 'good': AXE_UPGRADE_COSTS[1], 'strong': AXE_UPGRADE_COSTS[2] };\n            const cost = costs[level];\n            \n            if (firewoodCount < cost) {\n                showMessage(TRANSLATIONS[currentLang].notEnoughWood);\n                return;\n            }\n            \n            // Deduct cost and upgrade\n            firewoodCount -= cost;\n            axeLevel = level;\n            updateFirewoodInventory();\n            updateWeaponInventory();\n            \n            // Update UI\n            if (level === 'good') {\n                document.getElementById('craftGoodAxe').classList.add('owned');\n                document.getElementById('upgradeGoodAxe').style.display = 'none';\n                const ownedText = document.createElement('div');\n                ownedText.className = 'craftingItemOwned';\n                ownedText.textContent = 'Owned';\n                document.getElementById('craftGoodAxe').appendChild(ownedText);\n                \n                // Show Strong Axe option and hide placeholder\n                document.getElementById('strongAxePlaceholder').style.display = 'none';\n                document.getElementById('craftStrongAxe').classList.remove('hidden');\n            } else if (level === 'strong') {\n                document.getElementById('craftStrongAxe').classList.add('owned');\n                document.getElementById('upgradeStrongAxe').style.display = 'none';\n                const ownedText = document.createElement('div');\n                ownedText.className = 'craftingItemOwned';\n                ownedText.textContent = 'Owned';\n                document.getElementById('craftStrongAxe').appendChild(ownedText);\n            }\n            \n            updateCraftingButtonStates();\n        }\n        \n        function upgradeSkateboard(level) {\n            // Check if player has enough wood\n            const costs = [SKATEBOARD_UPGRADE_COSTS[0], SKATEBOARD_UPGRADE_COSTS[1], SKATEBOARD_UPGRADE_COSTS[2]];\n            const cost = costs[level - 1]; // Convert level 1-3 to index 0-2\n            \n            if (firewoodCount < cost) {\n                showMessage(TRANSLATIONS[currentLang].notEnoughWood);\n                return;\n            }\n            \n            // Deduct cost and upgrade\n            firewoodCount -= cost;\n            skateboardLevel = level;\n            hasSkateBoard = true;\n            updateFirewoodInventory();\n            \n            // Update UI\n            const levelNames = ['Basic', 'Fast', 'Super'];\n            const levelIds = ['craftBasicSkateboard', 'craftFastSkateboard', 'craftSuperSkateboard'];\n            const buttonIds = ['upgradeBasicSkateboard', 'upgradeFastSkateboard', 'upgradeSuperSkateboard'];\n            const nextLevelIds = ['craftFastSkateboard', 'craftSuperSkateboard', undefined];\n            \n            const currentId = levelIds[level - 1];\n            const buttonId = buttonIds[level - 1];\n            const nextId = nextLevelIds[level - 1];\n            \n            // Mark current level as owned\n            document.getElementById(currentId).classList.add('owned');\n            document.getElementById(buttonId).style.display = 'none';\n            const ownedText = document.createElement('div');\n            ownedText.className = 'craftingItemOwned';\n            ownedText.textContent = 'Owned';\n            document.getElementById(currentId).appendChild(ownedText);\n            \n            // Show next level if exists and hide placeholder\n            if (nextId) {\n                const placeholderIds = ['fastSkateboardPlaceholder', 'superSkateboardPlaceholder'];\n                const placeholderId = placeholderIds[level - 1]; // level 1->0, level 2->1\n                if (placeholderId) {\n                    document.getElementById(placeholderId).style.display = 'none';\n                }\n                document.getElementById(nextId).classList.remove('hidden');\n            }\n            \n            updateCraftingButtonStates();\n            updateSkateboardInventory();\n        }\n        \n        function upgradeSpear(level) {\n            // Check if player has enough wood\n            const costs = [SPEAR_UPGRADE_COSTS[0], SPEAR_UPGRADE_COSTS[1], SPEAR_UPGRADE_COSTS[2]];\n            const cost = costs[level - 1]; // Convert level 1-3 to index 0-2\n            \n            if (firewoodCount < cost) {\n                showMessage(TRANSLATIONS[currentLang].notEnoughWood);\n                return;\n            }\n            \n            // Deduct cost and upgrade\n            firewoodCount -= cost;\n            spearLevel = level;\n            hasSpear = true;\n            updateFirewoodInventory();\n            \n            // Update UI\n            const levelNames = ['Basic', 'Sharp', 'Poison'];\n            const levelIds = ['craftBasicSpear', 'craftSharpSpear', 'craftPoisonSpear'];\n            const buttonIds = ['upgradeBasicSpear', 'upgradeSharpSpear', 'upgradePoisonSpear'];\n            const nextLevelIds = ['craftSharpSpear', 'craftPoisonSpear', undefined];\n            \n            const currentId = levelIds[level - 1];\n            const buttonId = buttonIds[level - 1];\n            const nextId = nextLevelIds[level - 1];\n            \n            // Mark current level as owned\n            document.getElementById(currentId).classList.add('owned');\n            document.getElementById(buttonId).style.display = 'none';\n            const ownedText = document.createElement('div');\n            ownedText.className = 'craftingItemOwned';\n            ownedText.textContent = 'Owned';\n            document.getElementById(currentId).appendChild(ownedText);\n            \n            // Show next level if exists and hide placeholder\n            if (nextId) {\n                const placeholderIds = ['sharpSpearPlaceholder', 'poisonSpearPlaceholder'];\n                const placeholderId = placeholderIds[level - 1]; // level 1->0, level 2->1\n                if (placeholderId) {\n                    document.getElementById(placeholderId).style.display = 'none';\n                }\n                document.getElementById(nextId).classList.remove('hidden');\n            }\n            \n            updateCraftingButtonStates();\n            updateWeaponInventory();\n        }\n        \n        function resetCraftingUI() {\n            // Reset axe UI to starting state\n            document.getElementById('craftGoodAxe').classList.remove('owned', 'hidden');\n            document.getElementById('craftStrongAxe').classList.add('hidden');\n            document.getElementById('strongAxePlaceholder').style.display = 'flex';\n            \n            // Remove any owned text elements\n            const goodAxeOwned = document.getElementById('craftGoodAxe').querySelector('.craftingItemOwned');\n            if (goodAxeOwned) goodAxeOwned.remove();\n            const strongAxeOwned = document.getElementById('craftStrongAxe').querySelector('.craftingItemOwned');\n            if (strongAxeOwned) strongAxeOwned.remove();\n            \n            // Show upgrade buttons\n            const upgradeGoodAxe = document.getElementById('upgradeGoodAxe');\n            const upgradeStrongAxe = document.getElementById('upgradeStrongAxe');\n            if (upgradeGoodAxe) upgradeGoodAxe.style.display = 'block';\n            if (upgradeStrongAxe) upgradeStrongAxe.style.display = 'block';\n            \n            // Reset skateboard UI to starting state\n            document.getElementById('craftBasicSkateboard').classList.remove('owned', 'hidden');\n            document.getElementById('craftFastSkateboard').classList.add('hidden');\n            document.getElementById('craftSuperSkateboard').classList.add('hidden');\n            document.getElementById('fastSkateboardPlaceholder').style.display = 'flex';\n            document.getElementById('superSkateboardPlaceholder').style.display = 'flex';\n            \n            // Remove any skateboard owned text elements\n            const basicSkateboardOwned = document.getElementById('craftBasicSkateboard').querySelector('.craftingItemOwned');\n            if (basicSkateboardOwned) basicSkateboardOwned.remove();\n            const fastSkateboardOwned = document.getElementById('craftFastSkateboard').querySelector('.craftingItemOwned');\n            if (fastSkateboardOwned) fastSkateboardOwned.remove();\n            const superSkateboardOwned = document.getElementById('craftSuperSkateboard').querySelector('.craftingItemOwned');\n            if (superSkateboardOwned) superSkateboardOwned.remove();\n            \n            // Reset spear UI to starting state\n            document.getElementById('craftBasicSpear').classList.remove('owned', 'hidden');\n            document.getElementById('craftSharpSpear').classList.add('hidden');\n            document.getElementById('craftPoisonSpear').classList.add('hidden');\n            document.getElementById('sharpSpearPlaceholder').style.display = 'flex';\n            document.getElementById('poisonSpearPlaceholder').style.display = 'flex';\n            \n            // Remove any spear owned text elements\n            const basicSpearOwned = document.getElementById('craftBasicSpear').querySelector('.craftingItemOwned');\n            if (basicSpearOwned) basicSpearOwned.remove();\n            const sharpSpearOwned = document.getElementById('craftSharpSpear').querySelector('.craftingItemOwned');\n            if (sharpSpearOwned) sharpSpearOwned.remove();\n            const poisonSpearOwned = document.getElementById('craftPoisonSpear').querySelector('.craftingItemOwned');\n            if (poisonSpearOwned) poisonSpearOwned.remove();\n            \n            // Show spear buttons\n            const upgradeBasicSpear = document.getElementById('upgradeBasicSpear');\n            const upgradeSharpSpear = document.getElementById('upgradeSharpSpear');\n            const upgradePoisonSpear = document.getElementById('upgradePoisonSpear');\n            if (upgradeBasicSpear) upgradeBasicSpear.style.display = 'block';\n            if (upgradeSharpSpear) upgradeSharpSpear.style.display = 'block';\n            if (upgradePoisonSpear) upgradePoisonSpear.style.display = 'block';\n            \n            // Show skateboard buttons\n            const upgradeBasicSkateboard = document.getElementById('upgradeBasicSkateboard');\n            const upgradeFastSkateboard = document.getElementById('upgradeFastSkateboard');\n            const upgradeSuperSkateboard = document.getElementById('upgradeSuperSkateboard');\n            if (upgradeBasicSkateboard) upgradeBasicSkateboard.style.display = 'block';\n            if (upgradeFastSkateboard) upgradeFastSkateboard.style.display = 'block';\n            if (upgradeSuperSkateboard) upgradeSuperSkateboard.style.display = 'block';\n            \n            // Remove any campfire requirement text elements\n            const campfireRequirements = document.querySelectorAll('.campfire-requirement');\n            campfireRequirements.forEach(req => req.remove());\n            \n            // Update button states to reflect reset\n            updateCraftingButtonStates();\n        }\n        \n        function updateCraftingButtonStates() {\n            // Helper function to update button based on campfire level requirement\n            function updateButtonWithCampfireReq(buttonId, requiredLevel, isOwned, canCraft, cost) {\n                const button = document.getElementById(buttonId);\n                if (!button) return;\n                \n                // Remove any existing requirement text\n                const existingReq = button.parentNode.querySelector('.campfire-requirement');\n                if (existingReq) existingReq.remove();\n                \n                if (isOwned) {\n                    // Item is already owned, hide button completely\n                    button.style.display = 'none';\n                } else if (campfire.level < requiredLevel) {\n                    // Hide button and show requirement text\n                    button.style.display = 'none';\n                    const reqText = document.createElement('div');\n                    reqText.className = 'campfire-requirement';\n                    const _rt = TRANSLATIONS[currentLang].requiresCampfire(requiredLevel).split('\\n');\n                    reqText.innerHTML = _rt.join('<br>');\n                    reqText.style.cssText = 'color: red; font-size: 22px; text-align: center; margin-top: 8px; margin-bottom: 6px; line-height: 1.2;';\n                    button.parentNode.appendChild(reqText);\n                } else {\n                    // Show button and update state normally\n                    button.style.display = 'block';\n                    button.disabled = !canCraft || firewoodCount < cost;\n                }\n            }\n            \n            // Update axe buttons with campfire level requirements\n            // Good Axe requires campfire level 3, Strong Axe requires campfire level 4\n            updateButtonWithCampfireReq('upgradeGoodAxe', 3, axeLevel !== 'old', \n                                      axeLevel === 'old', AXE_UPGRADE_COSTS[1]);\n            updateButtonWithCampfireReq('upgradeStrongAxe', 4, axeLevel === 'strong', \n                                      axeLevel === 'good', AXE_UPGRADE_COSTS[2]);\n            \n            // Update skateboard buttons with campfire level requirements  \n            // Basic Skateboard requires campfire level 2, Fast requires level 3, Super requires level 4\n            updateButtonWithCampfireReq('upgradeBasicSkateboard', 2, skateboardLevel >= 1, \n                                      skateboardLevel === 0, SKATEBOARD_UPGRADE_COSTS[0]);\n            updateButtonWithCampfireReq('upgradeFastSkateboard', 3, skateboardLevel >= 2,\n                                      skateboardLevel === 1, SKATEBOARD_UPGRADE_COSTS[1]);\n            updateButtonWithCampfireReq('upgradeSuperSkateboard', 4, skateboardLevel >= 3,\n                                      skateboardLevel === 2, SKATEBOARD_UPGRADE_COSTS[2]);\n            \n            // Update spear buttons with campfire level requirements\n            // Basic Spear requires campfire level 2, Sharp requires level 3, Poison requires level 4  \n            updateButtonWithCampfireReq('upgradeBasicSpear', 2, spearLevel >= 1,\n                                      spearLevel === 0, SPEAR_UPGRADE_COSTS[0]);\n            updateButtonWithCampfireReq('upgradeSharpSpear', 3, spearLevel >= 2,\n                                      spearLevel === 1, SPEAR_UPGRADE_COSTS[1]);\n            updateButtonWithCampfireReq('upgradePoisonSpear', 4, spearLevel >= 3,\n                                      spearLevel === 2, SPEAR_UPGRADE_COSTS[2]);\n        }\n        \n        function updateCraftingIcons() {\n            // Set axe icons\n            const oldAxeIcon = document.getElementById('oldAxeIcon');\n            const goodAxeIcon = document.getElementById('goodAxeIcon');\n            const strongAxeIcon = document.getElementById('strongAxeIcon');\n            \n            if (oldAxeIcon && assetCache['sb_axe']) {\n                oldAxeIcon.src = assetCache['sb_axe'].src;\n            }\n            if (goodAxeIcon && assetCache['sb_axe']) {\n                goodAxeIcon.src = assetCache['sb_axe'].src;\n            }\n            if (strongAxeIcon && assetCache['red_axe']) {\n                strongAxeIcon.src = assetCache['red_axe'].src;\n            }\n            \n            // Set spear icons\n            const basicSpearIcon = document.getElementById('basicSpearIcon');\n            const sharpSpearIcon = document.getElementById('sharpSpearIcon');\n            const poisonSpearIcon = document.getElementById('poisonSpearIcon');\n            \n            // Set spear icons with correct assets for each level\n            if (basicSpearIcon && assetCache['sb_spear']) {\n                basicSpearIcon.src = assetCache['sb_spear'].src;\n            }\n            if (sharpSpearIcon && assetCache['sb_spear']) {\n                sharpSpearIcon.src = assetCache['sb_spear'].src;\n            }\n            if (poisonSpearIcon && assetCache['minecraft_poison_spear']) {\n                poisonSpearIcon.src = assetCache['minecraft_poison_spear'].src;\n            }\n            \n            // Set skateboard icons\n            const basicSkateboardIcon = document.getElementById('basicSkateboardIcon');\n            const fastSkateboardIcon = document.getElementById('fastSkateboardIcon');\n            const superSkateboardIcon = document.getElementById('superSkateboardIcon');\n            \n            if (basicSkateboardIcon && assetCache['sb_skateboard']) {\n                basicSkateboardIcon.src = assetCache['sb_skateboard'].src;\n            }\n            if (fastSkateboardIcon && assetCache['blue_skateboard']) {\n                fastSkateboardIcon.src = assetCache['blue_skateboard'].src;\n            }\n            if (superSkateboardIcon && assetCache['gold_skateboard']) {\n                superSkateboardIcon.src = assetCache['gold_skateboard'].src;\n            }\n            \n            // Set wood icons\n            const woodIcons = document.querySelectorAll('.craftingItemCostIcon');\n            woodIcons.forEach(icon => {\n                if (assetCache['sb_firewood']) {\n                    icon.src = assetCache['sb_firewood'].src;\n                }\n            });\n        }\n        \n        function updateCraftingCosts() {\n            // Update axe cost displays from constants\n            const goodAxeCost = document.getElementById('goodAxeCost');\n            const strongAxeCost = document.getElementById('strongAxeCost');\n            \n            if (goodAxeCost) {\n                goodAxeCost.textContent = AXE_UPGRADE_COSTS[1];\n            }\n            if (strongAxeCost) {\n                strongAxeCost.textContent = AXE_UPGRADE_COSTS[2];\n            }\n            \n            // Update spear cost displays from constants\n            const basicSpearCost = document.getElementById('basicSpearCost');\n            const sharpSpearCost = document.getElementById('sharpSpearCost');\n            const poisonSpearCost = document.getElementById('poisonSpearCost');\n            \n            if (basicSpearCost) {\n                basicSpearCost.textContent = SPEAR_UPGRADE_COSTS[0];\n            }\n            if (sharpSpearCost) {\n                sharpSpearCost.textContent = SPEAR_UPGRADE_COSTS[1];\n            }\n            if (poisonSpearCost) {\n                poisonSpearCost.textContent = SPEAR_UPGRADE_COSTS[2];\n            }\n            \n            // Update skateboard cost displays from constants\n            const basicSkateboardCost = document.getElementById('basicSkateboardCost');\n            const fastSkateboardCost = document.getElementById('fastSkateboardCost');\n            const superSkateboardCost = document.getElementById('superSkateboardCost');\n            \n            if (basicSkateboardCost) {\n                basicSkateboardCost.textContent = SKATEBOARD_UPGRADE_COSTS[0];\n            }\n            if (fastSkateboardCost) {\n                fastSkateboardCost.textContent = SKATEBOARD_UPGRADE_COSTS[1];\n            }\n            if (superSkateboardCost) {\n                superSkateboardCost.textContent = SKATEBOARD_UPGRADE_COSTS[2];\n            }\n        }\n        \n        function updateCraftButtonVisibility() {\n            const craftButton = document.getElementById('craftButton');\n            if (!craftButton) return;\n            \n            // Only show craft button if campfire is level 2 or higher\n            if (campfire.level < 2) {\n                craftButton.classList.remove('visible');\n                craftButton.style.pointerEvents = 'none'; // Disable pointer events\n                return;\n            }\n            \n            // Check if player is within 150px radius of workstation\n            const workstationDx = player.x - workstation.x;\n            const workstationDy = player.y - workstation.y;\n            const workstationDistance = Math.sqrt(workstationDx * workstationDx + workstationDy * workstationDy);\n            \n            if (workstationDistance < 150) {\n                // Position craft button above workstation\n                const screenX = workstation.x - camera.x;\n                const screenY = workstation.y - camera.y - 80; // 80px above workstation\n                \n                craftButton.style.left = (screenX - 60) + 'px'; // Center button (now wider with +50% padding)\n                craftButton.style.top = screenY + 'px';\n                craftButton.classList.add('visible');\n                craftButton.style.pointerEvents = 'all'; // Enable pointer events when visible\n            } else {\n                craftButton.classList.remove('visible');\n                craftButton.style.pointerEvents = 'none'; // Disable pointer events when invisible\n            }\n        }\n        \n        function updateWardrobeButtonVisibility() {\n            const wardrobeButton = document.getElementById('wardrobeButton');\n            if (!wardrobeButton) return;\n            \n            // Check if player is within 150px radius of wardrobe\n            const wardrobeDx = player.x - wardrobe.x;\n            const wardrobeDy = player.y - wardrobe.y;\n            const wardrobeDistance = Math.sqrt(wardrobeDx * wardrobeDx + wardrobeDy * wardrobeDy);\n            \n            if (wardrobeDistance < 150) {\n                // Position wardrobe button above wardrobe\n                const screenX = wardrobe.x - camera.x;\n                const screenY = wardrobe.y - camera.y - 80; // 80px above wardrobe\n                \n                wardrobeButton.style.left = (screenX - 60) + 'px'; // Center button\n                wardrobeButton.style.top = screenY + 'px';\n                wardrobeButton.classList.add('visible');\n                wardrobeButton.style.pointerEvents = 'all'; // Enable pointer events when visible\n            } else {\n                wardrobeButton.classList.remove('visible');\n                wardrobeButton.style.pointerEvents = 'none'; // Disable pointer events when invisible\n            }\n        }\n        \n        function showGameOverScreen() {\n            // Stop the game loop\n            isGameRunning = false;\n            \n            // Hide crafting UI\n            const craftButton = document.getElementById('craftButton');\n            const craftingDialog = document.getElementById('craftingDialog');\n            const craftingBackdrop = document.getElementById('craftingBackdrop');\n            \n            if (craftButton) {\n                craftButton.classList.remove('visible');\n                craftButton.style.display = 'none'; // Completely hide it\n                craftButton.style.pointerEvents = 'none'; // Disable pointer events\n            }\n            \n            if (craftingDialog) {\n                craftingDialog.classList.remove('visible');\n            }\n            \n            if (craftingBackdrop) {\n                craftingBackdrop.classList.remove('visible');\n            }\n            \n            // Create game over overlay\n            const gameOverOverlay = document.createElement('div');\n            gameOverOverlay.id = 'gameOverOverlay';\n            gameOverOverlay.style.position = 'absolute';\n            gameOverOverlay.style.top = '0';\n            gameOverOverlay.style.left = '0';\n            gameOverOverlay.style.width = '100%';\n            gameOverOverlay.style.height = '100%';\n            gameOverOverlay.style.background = 'rgba(10, 20, 50, 0.95)';\n            gameOverOverlay.style.display = 'flex';\n            gameOverOverlay.style.flexDirection = 'column';\n            gameOverOverlay.style.justifyContent = 'center';\n            gameOverOverlay.style.alignItems = 'center';\n            gameOverOverlay.style.zIndex = '1000';\n            gameOverOverlay.style.pointerEvents = 'all';\n            \n            // Game over text\n            const gameOverText = document.createElement('div');\n            gameOverText.textContent = TRANSLATIONS[currentLang].gameOver;\n            gameOverText.style.color = '#ffcc00';\n            gameOverText.style.textShadow = '0 0 20px #ff9900';\n            gameOverText.style.fontSize = '60px';\n            gameOverText.style.fontFamily = 'Solitreo, cursive';\n            gameOverText.style.textShadow = '3px 3px 0 black, -3px -3px 0 black, 3px -3px 0 black, -3px 3px 0 black';\n            gameOverText.style.marginBottom = '40px';\n            gameOverText.style.textAlign = 'center';\n            \n            // Try again button\n            const tryAgainButton = document.createElement('button');\n            tryAgainButton.textContent = TRANSLATIONS[currentLang].tryAgain;\n            tryAgainButton.style.fontSize = '40px';\n            tryAgainButton.style.fontFamily = 'Solitreo, cursive';\n            tryAgainButton.style.padding = '20px 40px';\n            tryAgainButton.style.background = '#1a3a6b';\n            tryAgainButton.style.color = '#ffcc00';\n            tryAgainButton.style.border = '3px solid #ffcc00';\n            tryAgainButton.style.textShadow = '0 0 8px #ff9900';\n            tryAgainButton.style.borderRadius = '15px';\n            tryAgainButton.style.cursor = 'pointer';\n            tryAgainButton.style.pointerEvents = 'all';\n            \n            tryAgainButton.addEventListener('click', () => {\n                resetGame();\n            });\n            \n            gameOverOverlay.appendChild(gameOverText);\n            gameOverOverlay.appendChild(tryAgainButton);\n            document.getElementById('ui').appendChild(gameOverOverlay);\n        }\n        \n        function showVictoryScreen() {\n            // Stop the game\n            isGameRunning = false;\n\n            // Hide craft button\n            const craftButton = document.getElementById('craftButton');\n            if (craftButton) {\n                craftButton.classList.remove('visible');\n                craftButton.style.display = 'none';\n            }\n\n            // Make children disappear\n            children.forEach(child => {\n                child.isFollowing = false;\n                child.isVisible = false;\n            });\n\n            // Submit score to leaderboard - inverted time so faster = higher score\n            const scoreToSubmit = Math.max(1, Math.floor(999999 - gameTimer));\n            if (window.lib && window.lib.addPlayerScoreToLeaderboard) {\n                window.lib.addPlayerScoreToLeaderboard(scoreToSubmit, 10).catch(() => {});\n            }\n\n            // Create victory overlay\n            const victoryOverlay = document.createElement('div');\n            victoryOverlay.id = 'victoryOverlay';\n            victoryOverlay.style.position = 'absolute';\n            victoryOverlay.style.top = '0';\n            victoryOverlay.style.left = '0';\n            victoryOverlay.style.width = '100%';\n            victoryOverlay.style.height = '100%';\n            victoryOverlay.style.background = '#021525';\n            victoryOverlay.style.display = 'flex';\n            victoryOverlay.style.flexDirection = 'column';\n            victoryOverlay.style.justifyContent = 'center';\n            victoryOverlay.style.alignItems = 'center';\n            victoryOverlay.style.zIndex = '1000';\n            victoryOverlay.style.pointerEvents = 'all';\n            \n            // Victory text\n            const victoryText = document.createElement('div');\n            const currentDay = window.gameConfig.ui.day;\n            victoryText.innerHTML = TRANSLATIONS[currentLang].allRescued(currentDay);\n            victoryText.style.color = '#ffcc00';\n            victoryText.style.fontSize = '60px';\n            victoryText.style.fontFamily = 'Solitreo, cursive';\n            victoryText.style.textShadow = '3px 3px 0 black, -3px -3px 0 black, 3px -3px 0 black, -3px 3px 0 black';\n            victoryText.style.marginBottom = '40px';\n            victoryText.style.textAlign = 'center';\n            victoryText.style.lineHeight = '1.2';\n            \n            // Keep playing button\n            const keepPlayingButton = document.createElement('button');\n            keepPlayingButton.textContent = TRANSLATIONS[currentLang].keepPlaying;\n            keepPlayingButton.style.fontSize = '40px';\n            keepPlayingButton.style.fontFamily = 'Solitreo, cursive';\n            keepPlayingButton.style.padding = '20px 40px';\n            keepPlayingButton.style.border = 'none';\n            keepPlayingButton.style.backgroundColor = '#5d7a31';\n            keepPlayingButton.style.color = 'white';\n            keepPlayingButton.style.cursor = 'pointer';\n            keepPlayingButton.style.borderRadius = '10px';\n            keepPlayingButton.style.textShadow = '2px 2px 0 black';\n            \n            // Button hover effect\n            keepPlayingButton.addEventListener('mouseenter', () => {\n                keepPlayingButton.style.backgroundColor = '#6a8c4a';\n            });\n            keepPlayingButton.addEventListener('mouseleave', () => {\n                keepPlayingButton.style.backgroundColor = '#5d7a31';\n            });\n            \n            // Button click handler\n            keepPlayingButton.addEventListener('click', () => {\n                // Remove victory overlay\n                victoryOverlay.remove();\n\n                // Restore craft button\n                const craftButton = document.getElementById('craftButton');\n                if (craftButton) {\n                    craftButton.style.display = '';\n                }\n\n                // Resume the game\n                isGameRunning = true;\n                requestAnimationFrame(gameLoop);\n            });\n            \n            // Add elements to overlay\n            victoryOverlay.appendChild(victoryText);\n            victoryOverlay.appendChild(keepPlayingButton);\n            \n            // Add overlay to page\n            document.getElementById('ui').appendChild(victoryOverlay);\n        }\n\n        function resetGame() {\n            // Reset all game state to Day 1\n            window.gameConfig.ui.day = 1;\n            player.health = 100;\n            player.hunger = 100;\n            player.hungerTimer = 0;\n            player.x = window.gameConfig.player.startX;\n            player.y = window.gameConfig.player.startY;\n            player.targetX = player.x;\n            player.targetY = player.y;\n            player.level = 1;\n            // Player has no XP system anymore\n            \n            // Reset craft button properly\n            const craftButton = document.getElementById('craftButton');\n            if (craftButton) {\n                craftButton.style.display = ''; // Remove the 'display: none' override\n                craftButton.classList.remove('visible'); // Remove visible class\n                craftButton.style.pointerEvents = 'none'; // Disable pointer events initially\n                // Clear any positioning styles\n                craftButton.style.left = '';\n                craftButton.style.top = '';\n            }\n            \n            // Reset crafting arrow\n            craftingArrow.visible = false;\n            craftingArrow.hidden = false;\n            craftingArrow.bobTimer = 0;\n\n            // Reset and show first tree arrow\n            firstTreeArrow.visible = true;\n            firstTreeArrow.bobTimer = 0;\n\n            // Reset and hide campfire arrow\n            campfireArrow.visible = false;\n            campfireArrow.bobTimer = 0;\n            \n            // Reset bed\n            bed.childrenRescued = 0;\n            \n            // Reset radar\n            radar.enabled = false;\n            \n            // Reset camera\n            camera.x = player.x - canvas.width / 2;\n            camera.y = player.y - canvas.height / 2;\n            \n            // Reset day/night cycle\n            dayNightTimer = 0;\n            isNight = false;\n            dayNightTransitioning = false;\n            gameSystemsStarted = false; // Reset active status of day/night cycle, campfire, hunger, etc.\n            anyTreeChopped = false;\n            firstWoodPickedUp = false;\n            window.nightApproachingWarned = false;\n            window.deerDespawnedToday = false;\n\n            // Ensure Day 1 starts in full daylight\n            const overlay = document.getElementById('dayNightOverlay');\n            if (overlay) {\n                overlay.style.opacity = '0';\n            }\n            \n            // Reset campfire\n            campfire.fireTimer = CAMPFIRE_STARTING_TIMER;\n            campfire.fireIntensity = CAMPFIRE_STARTING_INTENSITY;\n            campfire.fireParticles = [];\n            campfire.smokeParticles = [];\n            campfire.level = 1;\n            campfire.xp = 0;\n            campfire.maxXp = CAMPFIRE_XP_THRESHOLDS[0];\n            campfire.levelUpEffect = false;\n            campfire.levelUpTimer = 0;\n            \n            // Clear wood transfers\n            woodTransfers = [];\n            \n            // Clear meat transfers\n            meatTransfers = [];\n            \n            // Clear all entities\n            wolves = [];\n            bears = [];\n            frogs = [];\n            deer = [];\n            firewoodPiles = [];\n            meatPiles = [];\n            poisonSpears = [];\n            children = [];\n            childrenRescued = 0;\n            window.victoryTriggered = false;\n            gameTimer = 0;\n            updateGameTimerDisplay();\n            // Hide timer until first wood is picked up again\n            const timerEl = document.getElementById('gameTimer');\n            if (timerEl) timerEl.style.display = 'none';\n            \n            // Reset help bubble\n            helpBubbleTimer = 0;\n            helpBubbleVisible = false;\n            \n            // Reset enemy spawn timings\n            lastEnemySpawnTime = {\n                wolf: 0,\n                bear: 0\n            };\n            wolfDamageCooldowns.clear();\n            bearDamageCooldowns.clear();\n            \n            // Clear environment objects to regenerate them\n            trees.clear();\n            rocksAndFlowers.clear();\n            \n            // Reset inventory and equipment\n            firewoodCount = 0;\n            meatCount = 0;\n            hasPoisonSpear = false;\n            currentWeapon = 'axe';\n            axeLevel = 'old'; // Reset axe to starting level\n            spearLevel = 0; // Reset spear to no spear\n            hasSpear = false; // Player must craft spear\n            hasSkateBoard = false; // Player must craft skateboard\n            skateboardEquipped = false;\n            skateboardLevel = 0;\n            window.gameConfig.frogsKilled = 0;\n            window.gameConfig.poisonSpearSpawned = false;\n            window.gameConfig.firstFrogSpawned = false;\n            \n            // Clear particles\n            if (window.allParticles) {\n                window.allParticles = [];\n            }\n            \n            // Update UI\n            { const t = TRANSLATIONS[currentLang]; document.getElementById('dayCounter').textContent = currentLang === 'ar' ? `${t.day} 1` : 'Day 1'; }\n            // Reset skin to SpongeBob\n            if (!window.gameConfig.inventory || !window.gameConfig.inventory.currentSkinId) {\n                currentSkinId = 'spongebob_skin';\n            }\n            updateHealthBar();\n            updateHungerBar();\n            updateFireBar();\n            updateWeaponInventory();\n            updateSkateboardInventory();\n            updateFirewoodInventory();\n            updateMeatInventory();\n            updateXPBar();\n            resetCraftingUI();\n            \n            // Re-initialize children at their starting positions (only if late assets are loaded)\n            if (lateAssetsLoaded) {\n                initializeChildren();\n            }\n\n            // Remove day/night overlay (reuse the overlay variable from above)\n            overlay.style.opacity = '0';\n            \n            // Remove game over overlay\n            const gameOverOverlay = document.getElementById('gameOverOverlay');\n            if (gameOverOverlay) {\n                gameOverOverlay.remove();\n            }\n            \n            // Restart the game loop\n            isGameRunning = true;\n            requestAnimationFrame(gameLoop);\n        }\n        \n        function updateAllParticles(deltaTime) {\n            if (!window.allParticles) return;\n            \n            window.allParticles = window.allParticles.filter(particle => {\n                particle.life -= deltaTime / particle.maxLife;\n                // Update world position\n                particle.worldX += particle.vx * deltaTime;\n                particle.worldY += particle.vy * deltaTime;\n                particle.vy += particle.gravity * deltaTime; // Apply gravity\n                \n                // Update oscillation for white particles\n                if (particle.textureType === 'white' && particle.oscillationTimer !== undefined) {\n                    particle.oscillationTimer += deltaTime * particle.oscillationSpeed;\n                    \n                    // Oscillate between 50% and 100% using sine wave\n                    const oscillation = 0.75 + 0.25 * Math.sin(particle.oscillationTimer); // 0.5 to 1.0\n                    \n                    // Apply oscillation to both size and opacity\n                    particle.size = particle.baseSize * oscillation;\n                    particle.opacity = particle.baseOpacity * oscillation;\n                }\n                \n                // Simple ground bounce using particle's individual ground level\n                if (particle.groundY && particle.worldY > particle.groundY && particle.vy > 0 && particle.bounceCount < particle.maxBounces) {\n                    particle.vy *= -0.6; // Bounce with energy loss\n                    particle.vx *= 0.8; // Friction\n                    particle.bounceCount++;\n                }\n                \n                return particle.life > 0;\n            });\n        }\n        \n        function updateTrees(deltaTime) {\n            if (gameMode === 'edit') return;\n            \n            const visibleTrees = getVisibleTrees();\n            visibleTrees.forEach(tree => {\n                // Update shake animation\n                if (tree.shakeTimer > 0) {\n                    tree.shakeTimer -= deltaTime;\n                    if (tree.shakeTimer <= 0) {\n                        tree.shakeIntensity = 0;\n                    }\n                }\n                \n                // Update health bar timer\n                if (tree.healthBarTimer > 0) {\n                    tree.healthBarTimer -= deltaTime;\n                }\n                \n                // Update destruction animation\n                if (tree.destroyed && tree.destructionTimer !== undefined) {\n                    tree.destructionTimer += deltaTime;\n                    const progress = tree.destructionTimer / tree.destructionDuration;\n                    \n                    if (progress <= 0.5) {\n                        // First half: scale up to 120%\n                        tree.destructionScale = 1 + (progress * 2) * 0.2; // 1.0 to 1.2\n                    } else {\n                        // Second half: scale down to 0%\n                        tree.destructionScale = 1.2 - ((progress - 0.5) * 2) * 1.2; // 1.2 to 0\n                    }\n                    \n                    // Mark for removal when animation is complete\n                    if (progress >= 1) {\n                        tree.fullyDestroyed = true;\n                    }\n                }\n            });\n        }\n        \n        function updateRocksAndFlowers(deltaTime) {\n            if (gameMode === 'edit') return;\n            \n            const visibleRocksAndFlowers = getVisibleRocksAndFlowers();\n            visibleRocksAndFlowers.forEach(obj => {\n                // Update shake animation\n                if (obj.shakeTimer > 0) {\n                    obj.shakeTimer -= deltaTime;\n                    if (obj.shakeTimer <= 0) {\n                        obj.shakeIntensity = 0;\n                    }\n                }\n                \n                // Update health bar timer\n                if (obj.healthBarTimer > 0) {\n                    obj.healthBarTimer -= deltaTime;\n                }\n                \n                // Update destruction animation\n                if (obj.destroyed && obj.destructionTimer !== undefined) {\n                    obj.destructionTimer += deltaTime;\n                    const progress = obj.destructionTimer / obj.destructionDuration;\n                    \n                    if (progress <= 0.5) {\n                        // First half: scale up to 120%\n                        obj.destructionScale = 1 + (progress * 2) * 0.2; // 1.0 to 1.2\n                    } else {\n                        // Second half: scale down to 0%\n                        obj.destructionScale = 1.2 - ((progress - 0.5) * 2) * 1.2; // 1.2 to 0\n                    }\n                    \n                    // Mark for removal when animation is complete\n                    if (progress >= 1) {\n                        obj.fullyDestroyed = true;\n                    }\n                }\n            });\n        }\n        \n        function updateCamera(deltaTime) {\n            const targetCameraX = player.x - canvas.width / 2;\n            const targetCameraY = player.y - canvas.height / 2;\n            \n            camera.x += (targetCameraX - camera.x) * CAMERA_SMOOTHING;\n            camera.y += (targetCameraY - camera.y) * CAMERA_SMOOTHING;\n        }\n        \n        function updateCampfire(deltaTime) {\n            if (gameMode === 'edit') return;\n\n            // On Day 1, freeze fire decay until first tree is chopped\n            if (!gameSystemsStarted) {\n                // Keep fire at starting intensity but still spawn particles\n                campfire.fireIntensity = CAMPFIRE_STARTING_INTENSITY;\n                campfire.fireTimer = CAMPFIRE_STARTING_TIMER;\n            } else {\n                // Apply decay rate based on campfire level (0-indexed array)\n                const decayRate = CAMPFIRE_DECAY_RATES[campfire.level - 1] || 1.0;\n                campfire.fireTimer += deltaTime * decayRate;\n\n                // Cap the timer so it doesn't grow indefinitely when fire is out\n                const fireDuration = window.gameConfig.fireDuration || 10;\n                campfire.fireTimer = Math.min(campfire.fireTimer, fireDuration);\n\n                // Update fire intensity (gradually dies over time)\n                const previousIntensity = campfire.fireIntensity;\n                campfire.fireIntensity = Math.max(0, 1 - (campfire.fireTimer / fireDuration));\n                \n                // Check if campfire reached 20% of lifespan (80% intensity remaining)\n                if (previousIntensity > 0.2 && campfire.fireIntensity <= 0.2) {\n                    showMessage(TRANSLATIONS[currentLang].campfireAlmostOut, true);\n                }\n            }\n            \n            // Update shadow flicker\n            campfire.shadowFlicker += deltaTime * 20; // 2x faster rate\n            \n            // Spawn fire particles\n            if (campfire.fireIntensity > 0) {\n                const particleRate = campfire.fireIntensity * 8; // particles per second\n                // Gradually shrink spawn area as fire dies - from 80px to 0px\n                const spawnAreaWidth = 80 * campfire.fireIntensity;\n                const spawnAreaHeight = 40 * campfire.fireIntensity;\n                \n                for (let i = 0; i < particleRate * deltaTime; i++) {\n                    campfire.fireParticles.push({\n                        x: campfire.x + (Math.random() - 0.5) * spawnAreaWidth, // Shrinking spawn area\n                        y: campfire.y - 20 + (Math.random() - 0.5) * spawnAreaHeight, // Shrinking spawn area\n                        vx: -20 + Math.random() * 10, // Drift left\n                        vy: -50 - Math.random() * 30,\n                        life: 1.0,\n                        maxLife: 0.8 + Math.random() * 0.4,\n                        size: 4 + Math.random() * 6,\n                        color: Math.random() > 0.5 ? 'orange' : 'yellow',\n                        waveOffset: Math.random() * Math.PI * 2,\n                        waveSpeed: 2 + Math.random() * 2\n                    });\n                }\n                \n                // Spawn smoke particles (less frequent)\n                const smokeRate = campfire.fireIntensity * 2;\n                // Gradually shrink smoke spawn area as fire dies - from 60px to 0px\n                const smokeSpawnAreaWidth = 60 * campfire.fireIntensity;\n                const smokeSpawnAreaHeight = 20 * campfire.fireIntensity;\n                \n                for (let i = 0; i < smokeRate * deltaTime; i++) {\n                    campfire.smokeParticles.push({\n                        x: campfire.x + (Math.random() - 0.5) * smokeSpawnAreaWidth, // Shrinking spawn area\n                        y: campfire.y - 40 + (Math.random() - 0.5) * smokeSpawnAreaHeight, // Shrinking spawn area\n                        vx: -15 + Math.random() * 5, // Drift left\n                        vy: -30 - Math.random() * 20,\n                        life: 1.0,\n                        maxLife: 2.0 + Math.random() * 1.0,\n                        size: 8 + Math.random() * 12,\n                        waveOffset: Math.random() * Math.PI * 2,\n                        waveSpeed: 1 + Math.random()\n                    });\n                }\n            }\n            \n            // Update fire particles\n            campfire.fireParticles = campfire.fireParticles.filter(particle => {\n                particle.life -= deltaTime / particle.maxLife;\n                particle.x += particle.vx * deltaTime;\n                particle.y += particle.vy * deltaTime;\n                \n                // Add wave motion (except for level up particles)\n                if (!particle.isLevelUp) {\n                    particle.x += Math.sin(campfire.fireTimer * particle.waveSpeed + particle.waveOffset) * 10 * deltaTime;\n                }\n                \n                // Decelerate level up particles\n                if (particle.isLevelUp) {\n                    particle.vx *= 0.95;\n                    particle.vy *= 0.95;\n                }\n                \n                return particle.life > 0;\n            });\n            \n            // Update level up effect timer\n            if (campfire.levelUpEffect) {\n                campfire.levelUpTimer += deltaTime;\n                if (campfire.levelUpTimer > 1.5) {\n                    campfire.levelUpEffect = false;\n                }\n            }\n            \n            // Update fire bar\n            updateFireBar();\n            \n            // Update smoke particles\n            campfire.smokeParticles = campfire.smokeParticles.filter(particle => {\n                particle.life -= deltaTime / particle.maxLife;\n                particle.x += particle.vx * deltaTime;\n                particle.y += particle.vy * deltaTime;\n                \n                // Add wave motion\n                particle.x += Math.sin(campfire.fireTimer * particle.waveSpeed + particle.waveOffset) * 15 * deltaTime;\n                \n                return particle.life > 0;\n            });\n        }\n        \n        function updateDayNightCycle(deltaTime) {\n            // Don't progress day/night cycle during intro\n            if (introScreenActive) return;\n\n            // On Day 1, don't progress day/night cycle until first tree is chopped\n            if (window.gameConfig.ui.day === 1 && !gameSystemsStarted) {\n                // Keep it permanently daytime on Day 1 until first tree is chopped\n                dayNightTimer = 0;\n                isNight = false;\n                return;\n            }\n\n            // Lock night if a demonic deer exists\n            if (isNight) {\n                const demonicActive = deer.some(d => !d.fullyDestroyed && !d.destroyed && d.isDemonic);\n                if (demonicActive) {\n                    return;\n                }\n            }\n\n            if (gameMode === 'edit') return;\n\n            dayNightTimer += deltaTime;\n            const dayLength = window.gameConfig.dayLength || 300;\n            \n            // Deer despawning at middle of day is disabled (deer now flee at night end instead)\n            \n            // Issue warning if night is approaching\n            if (!isNight && dayNightTimer >= dayLength * 0.5 && !window.nightApproachingWarned) {\n                // Check if deer will be demonic (on 100th day)\n                const willBeDemonic = (window.gameConfig.ui.day % 100 === 0);\n                // Check if deer will be hungry (every 10th day - day 10, 20, 30, etc.)\n                const willBeHungry = window.gameConfig.ui.day % 10 === 0;\n                \n                const t = TRANSLATIONS[currentLang];\n                if (willBeDemonic) {\n                    showMessage(t.nightApproachingDemonic, false, '#FF0000');\n                } else if (willBeHungry) {\n                    showMessage(t.nightApproachingHungry, false, '#FF0000');\n                } else {\n                    showMessage(t.nightApproaching, false, '#8A2BE2');\n                }\n                playSound('sfx_night_warning', 0.9);\n                window.nightApproachingWarned = true;\n            }\n            \n            // Check for day/night transitions\n            if (!isNight && dayNightTimer >= dayLength) {\n                // Transition to night\n                isNight = true;\n                dayNightTransitioning = true;\n                const overlay = document.getElementById('dayNightOverlay');\n                overlay.style.opacity = '1';\n                \n                setTimeout(() => {\n                    dayNightTransitioning = false;\n                }, 5000);\n                \n            } else if (isNight && dayNightTimer >= dayLength * 2) {\n                // Trigger deer flee on night end (non-demonic)\n                deer.forEach(function(d){ if (!d.destroyed && !d.fullyDestroyed && !d.isDemonic) { d.fleeing = true; d.fleeTimer = 0; d.fleeDuration = (window.gameConfig.dayLength || 300) * 0.25; } });\n\n                // Transition to day and increment day counter\n                isNight = false;\n                dayNightTransitioning = true;\n                dayNightTimer = 0;\n                window.nightApproachingWarned = false; // Reset warning flag for next day\n                window.deerDespawnedToday = false; // Reset deer despawn flag for next day\n                \n                window.gameConfig.ui.day++;\n                { const t = TRANSLATIONS[currentLang]; document.getElementById('dayCounter').textContent = currentLang === 'ar' ? `${t.day} ${window.gameConfig.ui.day}` : `Day ${window.gameConfig.ui.day}`; }\n                \n                const overlay = document.getElementById('dayNightOverlay');\n                overlay.style.opacity = '0';\n                \n                setTimeout(() => {\n                    dayNightTransitioning = false;\n                }, 5000);\n                \n                // Check win condition\n                if (window.gameConfig.ui.day >= 99) {\n                    showMessage(TRANSLATIONS[currentLang].survived99);\n                }\n            }\n        }\n        \n        function updateMinimap() {\n            const minimap = document.getElementById('minimap');\n            \n            // Only show minimap if radar is enabled and player is near radar\n            if (!radar.enabled) {\n                minimap.style.display = 'none';\n                return;\n            }\n            \n            // Check if player is within range of radar base (bottom of radar asset)\n            const radarBaseY = radar.y + radar.size * 0.3; // Base is 30% down from center\n            const radarDx = player.x - radar.x;\n            const radarDy = player.y - radarBaseY;\n            const radarDistance = Math.sqrt(radarDx * radarDx + radarDy * radarDy);\n            const radarRange = 110; // Distance to activate minimap\n            \n            if (radarDistance > radarRange) {\n                minimap.style.display = 'none';\n                return;\n            } else {\n                minimap.style.display = 'block';\n            }\n            \n            const centerDot = minimap.querySelector('.minimap-center');\n            const playerDot = minimap.querySelector('.minimap-player');\n            \n            // Position center dot (campfire at world origin) in center of minimap\n            centerDot.style.left = '56px'; // 60px - 4px (half dot size)\n            centerDot.style.top = '56px';\n            \n            // Position player dot relative to world origin\n            const minimapSize = 120;\n            const worldViewSize = 17200; // 120px minimap represents 17200 world units (8600 radius)\n            const scale = minimapSize / worldViewSize;\n            \n            const playerMapX = 60 + (player.x * scale);\n            const playerMapY = 60 + (player.y * scale);\n            \n            // Clamp to minimap bounds\n            const clampedX = Math.max(3, Math.min(117, playerMapX));\n            const clampedY = Math.max(3, Math.min(117, playerMapY));\n            \n            playerDot.style.left = (clampedX - 3) + 'px';\n            playerDot.style.top = (clampedY - 3) + 'px';\n            \n            // Remove existing child dots\n            const existingChildDots = minimap.querySelectorAll('.minimap-child');\n            existingChildDots.forEach(dot => dot.remove());\n            \n            // Add dots for un-rescued children\n            children.forEach(child => {\n                // Only show visible, un-rescued children\n                if (child.isVisible !== false && !child.isFollowing) {\n                    const childMapX = 60 + (child.x * scale);\n                    const childMapY = 60 + (child.y * scale);\n                    \n                    // Only show children within minimap bounds\n                    if (childMapX >= 0 && childMapX <= minimapSize && childMapY >= 0 && childMapY <= minimapSize) {\n                        const childDot = document.createElement('div');\n                        childDot.className = 'minimap-dot minimap-child';\n                        childDot.style.width = '6px';\n                        childDot.style.height = '6px';\n                        childDot.style.background = '#ffff00'; // Yellow for children\n                        childDot.style.border = '1px solid #ff8800'; // Orange border\n                        childDot.style.boxShadow = '0 0 4px #ffff00';\n                        childDot.style.left = (childMapX - 3) + 'px';\n                        childDot.style.top = (childMapY - 3) + 'px';\n                        minimap.appendChild(childDot);\n                    }\n                }\n            });\n        }\n        \n        function drawParticles() {\n            // Draw smoke particles first (behind fire)\n            campfire.smokeParticles.forEach(particle => {\n                const screenX = particle.x - camera.x;\n                const screenY = particle.y - camera.y;\n                const alpha = particle.life * 0.6;\n                \n                ctx.fillStyle = `rgba(64, 64, 64, ${alpha})`;\n                ctx.beginPath();\n                ctx.arc(screenX, screenY, particle.size, 0, Math.PI * 2);\n                ctx.fill();\n            });\n            \n            // Draw fire particles\n            campfire.fireParticles.forEach(particle => {\n                const screenX = particle.x - camera.x;\n                const screenY = particle.y - camera.y;\n                const alpha = particle.life;\n                \n                if (particle.color === 'yellow') {\n                    ctx.fillStyle = `rgba(255, 255, 0, ${alpha})`;\n                } else {\n                    ctx.fillStyle = `rgba(255, 165, 0, ${alpha})`;\n                }\n                \n                ctx.beginPath();\n                ctx.arc(screenX, screenY, particle.size, 0, Math.PI * 2);\n                ctx.fill();\n            });\n            \n            // Draw all particles (voxel cubes with textures)\n            if (window.allParticles) {\n                window.allParticles.forEach(particle => {\n                    // Use world coordinates to make particles move with the world\n                    const screenX = particle.worldX - camera.x;\n                    const screenY = particle.worldY - camera.y;\n                    const alpha = particle.life;\n                    \n                    // Map texture types to asset IDs\n                    let textureAssetId, fallbackColor;\n                    switch (particle.textureType) {\n                        case 'green':\n                            textureAssetId = 'green_wood_particle';\n                            fallbackColor = 'rgba(34, 139, 34, ';\n                            break;\n                        case 'brown':\n                            textureAssetId = 'brown_wood_particle';\n                            fallbackColor = 'rgba(139, 69, 19, ';\n                            break;\n                        case 'grey':\n                            textureAssetId = 'grey_particle';\n                            fallbackColor = 'rgba(128, 128, 128, ';\n                            break;\n                        case 'red':\n                            textureAssetId = 'red_particle';\n                            fallbackColor = 'rgba(220, 20, 20, ';\n                            break;\n                        case 'white':\n                            textureAssetId = null; // No texture for white particles, draw as glowing circles\n                            fallbackColor = 'rgba(255, 255, 255, ';\n                            break;\n                        default:\n                            textureAssetId = 'green_wood_particle';\n                            fallbackColor = 'rgba(34, 139, 34, ';\n                    }\n                    \n                    // Special handling for white collection particles\n                    if (particle.textureType === 'white') {\n                        // Draw as solid white circles with oscillating size and opacity (no glow)\n                        const fadeAlpha = particle.life; // White particles fade throughout their life\n                        const finalOpacity = (particle.opacity || particle.baseOpacity || 1.0) * fadeAlpha; // Use oscillating opacity\n                        const finalSize = particle.size || particle.baseSize || 8; // Use oscillating size\n                        \n                        ctx.fillStyle = `rgba(255, 255, 255, ${finalOpacity})`;\n                        ctx.beginPath();\n                        ctx.arc(screenX, screenY, finalSize, 0, Math.PI * 2);\n                        ctx.fill();\n                    } else {\n                        const textureAsset = assetCache[textureAssetId];\n                        \n                        if (textureAsset && textureAsset.complete) {\n                            // Draw textured particle with fade only in last 30% of lifespan\n                            ctx.save();\n                            const fadeThreshold = 0.3; // Last 30% of life\n                            const fadeAlpha = particle.life <= fadeThreshold ? \n                                (particle.life / fadeThreshold) : 1.0;\n                            ctx.globalAlpha = fadeAlpha;\n                            ctx.drawImage(textureAsset, \n                                screenX - particle.size/2, screenY - particle.size/2, \n                                particle.size, particle.size);\n                            ctx.restore();\n                        } else {\n                            // Fallback to colored squares with fade only in last 30% of lifespan\n                            const fadeThreshold = 0.3; // Last 30% of life\n                            const fadeAlpha = particle.life <= fadeThreshold ? \n                                (particle.life / fadeThreshold) : 1.0;\n                            ctx.fillStyle = fallbackColor + fadeAlpha + ')';\n                            \n                            ctx.fillRect(screenX - particle.size/2, screenY - particle.size/2, \n                                       particle.size, particle.size);\n                        }\n                    }\n                });\n            }\n        }\n        \n        function drawObjectLabel(screenX, screenY, text) {\n            if (!text) return;\n            ctx.save();\n            ctx.font = 'bold 18px Solitreo, cursive';\n            ctx.textAlign = 'center';\n            ctx.textBaseline = 'bottom';\n            const metrics = ctx.measureText(text);\n            const padX = 14, padY = 6;\n            const w = metrics.width + padX * 2;\n            const h = 22 + padY;\n            const rx = screenX - w / 2;\n            const ry = screenY - h;\n            // Draw pill background\n            ctx.fillStyle = 'rgba(0, 0, 0, 0.55)';\n            ctx.strokeStyle = 'rgba(255, 200, 0, 0.45)';\n            ctx.lineWidth = 1.5;\n            const radius = 8;\n            ctx.beginPath();\n            ctx.moveTo(rx + radius, ry);\n            ctx.lineTo(rx + w - radius, ry);\n            ctx.quadraticCurveTo(rx + w, ry, rx + w, ry + radius);\n            ctx.lineTo(rx + w, ry + h - radius);\n            ctx.quadraticCurveTo(rx + w, ry + h, rx + w - radius, ry + h);\n            ctx.lineTo(rx + radius, ry + h);\n            ctx.quadraticCurveTo(rx, ry + h, rx, ry + h - radius);\n            ctx.lineTo(rx, ry + radius);\n            ctx.quadraticCurveTo(rx, ry, rx + radius, ry);\n            ctx.closePath();\n            ctx.fill();\n            ctx.stroke();\n            // Draw text outline\n            ctx.lineWidth = 3;\n            ctx.strokeStyle = 'black';\n            ctx.strokeText(text, screenX, screenY - 4);\n            ctx.fillStyle = '#ffffcc';\n            ctx.fillText(text, screenX, screenY - 4);\n            ctx.restore();\n        }\n\n        function getObjectLabelText(obj) {\n            const t = TRANSLATIONS[currentLang];\n            const isAr = currentLang === 'ar';\n            switch (obj.type) {\n                case 'sb_tree_1':\n                    return isAr ? '\u0645\u0631\u062c\u0627\u0646' : 'Coral';\n                case 'sb_tree_2':\n                    return isAr ? '\u0639\u0634\u0628 \u0627\u0644\u0628\u062d\u0631' : 'Kelp';\n                case 'sb_tree_3':\n                    return isAr ? '\u0634\u0642\u0627\u0626\u0642 \u0627\u0644\u0646\u0639\u0645\u0627\u0646' : 'Anemone';\n                case 'sb_rock':\n                    return isAr ? '\u0635\u062e\u0631\u0629' : 'Rock';\n                case 'sb_flower':\n                    return isAr ? '\u0646\u062c\u0645 \u0627\u0644\u0628\u062d\u0631' : 'Starfish';\n                case 'campfire':\n                    return null;\n                case 'workstation':\n                    return campfire.level >= 2 ? (isAr ? '\u0637\u0627\u0648\u0644\u0629 \u0627\u0644\u0635\u0646\u0639' : 'Workstation') : null;\n                case 'bed':\n                    return null; // Don't show label - bed displays children rescued count instead\n                case 'radar':\n                    return campfire.level >= 5 ? (isAr ? '\u0627\u0644\u0631\u0627\u062f\u0627\u0631' : 'Radar') : null;\n                case 'wardrobe':\n                    return isAr ? '\u0627\u0644\u062e\u0632\u0627\u0646\u0629' : 'Wardrobe';\n                case 'wolf':\n                    return isAr ? '\u0642\u0646\u062f\u064a\u0644 \u0628\u062d\u0631' : 'Jellyfish';\n                case 'bear':\n                    return isAr ? '\u0633\u0645\u0643\u0629 \u0645\u0636\u064a\u0626\u0629' : 'Anglerfish';\n                case 'frog':\n                    return isAr ? '\u062d\u0644\u0632\u0648\u0646' : 'Sea Snail';\n                case 'deer':\n                    if (obj.isDemonic) return isAr ? '\u063a\u0632\u0627\u0644\u0629 \u0634\u064a\u0637\u0627\u0646\u064a\u0629 \ud83d\udc79' : 'Demonic Deer \ud83d\udc79';\n                    if (obj.isHungry) return isAr ? '\u063a\u0632\u0627\u0644\u0629 \u062c\u0627\u0626\u0639\u0629 \ud83d\udd34' : 'Hungry Deer \ud83d\udd34';\n                    return isAr ? '\u063a\u0632\u0627\u0644\u0629 \u0627\u0644\u0631\u0639\u0628' : 'Horror Deer';\n                case 'firewood':\n                    return isAr ? '\u062d\u0637\u0628' : 'Firewood';\n                case 'meat':\n                    return isAr ? '\u0644\u062d\u0645' : 'Meat';\n                default:\n                    return null;\n            }\n        }\n\n        function render() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            \n            // Draw background\n            drawBackground();\n            \n            // Get visible objects and sort by Y position for proper layering\n            const visibleTrees = getVisibleTrees();\n            const visibleRocksAndFlowers = getVisibleRocksAndFlowers();\n            const visibleFirewood = firewoodPiles.filter(pile => !pile.fullyDestroyed);\n            const visibleMeat = meatPiles.filter(meat => !meat.fullyDestroyed);\n            const visiblePoisonSpears = poisonSpears.filter(spear => !spear.collected);\n            const allObjects = [...visibleTrees, \n                ...visibleRocksAndFlowers,\n                { x: player.x, y: player.y, type: 'player', size: player.size },\n                { x: campfire.x, y: campfire.y, type: 'campfire', size: 160 },\n                ...(campfire.level >= 3 ? [{ x: bed.x, y: bed.y, type: 'bed', size: bed.size }] : []),\n                ...(campfire.level >= 2 ? [{ x: workstation.x, y: workstation.y, type: 'workstation', size: workstation.size }] : []),\n                ...(campfire.level >= 5 ? [{ x: radar.x, y: radar.y, type: 'radar', size: radar.size }] : []),\n                { x: wardrobe.x, y: wardrobe.y, type: 'wardrobe', size: wardrobe.size },\n                ...visibleFirewood.map(pile => ({ x: pile.x, y: pile.y, type: 'firewood', size: pile.size, destructionScale: pile.destructionScale, originalY: pile.originalY, destroyed: pile.destroyed })),\n                ...visibleMeat.map(meat => ({ x: meat.x, y: meat.y, type: 'meat', size: meat.size, destructionScale: meat.destructionScale, originalY: meat.originalY, destroyed: meat.destroyed })),\n                ...visiblePoisonSpears.map(spear => ({ x: spear.x, y: spear.y, type: 'poisonSpear', size: spear.size, destructionScale: spear.destructionScale, destroyed: spear.destroyed })),\n                ...mapEnemiesToObjects('wolf'),\n                ...mapEnemiesToObjects('bear'),\n                ...frogs.map(frog => ({ x: frog.x, y: frog.y, type: 'frog', size: frog.size, bounceHeight: frog.bounceHeight, shakeTimer: frog.shakeTimer, shakeIntensity: frog.shakeIntensity, health: frog.health, maxHealth: frog.maxHealth, healthBarTimer: frog.healthBarTimer, destroyed: frog.destroyed, destructionScale: frog.destructionScale, originalY: frog.originalY, fullyDestroyed: frog.fullyDestroyed, movingRight: frog.movingRight })),\n                ...deer.map(deerEntity => ({ x: deerEntity.x, y: deerEntity.y, type: 'deer', size: deerEntity.size, bounceHeight: deerEntity.bounceHeight, shakeTimer: deerEntity.shakeTimer, shakeIntensity: deerEntity.shakeIntensity, health: deerEntity.health, maxHealth: deerEntity.maxHealth, healthBarTimer: deerEntity.healthBarTimer, destroyed: deerEntity.destroyed, destructionScale: deerEntity.destructionScale, originalY: deerEntity.originalY, fullyDestroyed: deerEntity.fullyDestroyed, movingRight: deerEntity.movingRight, isHungry: deerEntity.isHungry, isDemonic: deerEntity.isDemonic })),\n                ...children.filter(child => child.isVisible !== false).map(child => ({ x: child.x, y: child.y, type: 'child', size: child.size, assetId: child.assetId, jumpHeight: child.jumpHeight, movingRight: child.movingRight, isFollowing: child.isFollowing }))\n            ];\n            // Z-sort based on bottom of objects (isometric perspective)\n            // Offset Y by 35% of object height for better depth sorting\n            allObjects.sort((a, b) => {\n                const aSize = a.size || 50; // Default size\n                const bSize = b.size || 50;\n                const aBottom = a.y + (aSize * 0.35); // 35% down from center\n                const bBottom = b.y + (bSize * 0.35);\n                return aBottom - bBottom;\n            });\n            \n            // Draw shadows first\n            allObjects.forEach(obj => {\n                let screenX = obj.x - camera.x;\n                let screenY = obj.y - camera.y;\n                \n                // Apply shake effect to shadow X position only (not Y) for items that are shaking\n                if (obj.shakeTimer > 0) {\n                    const shakeAmount = obj.shakeIntensity * (obj.shakeTimer / 0.5);\n                    screenX += (Math.random() - 0.5) * shakeAmount; // Only move shadow on X-axis\n                    // Do not modify screenY - shadows stay at original Y position during shake\n                }\n                \n                if (obj.type === 'player') {\n                    // Player shadow scales down when bouncing (65% at max bounce)\n                    const shadowScale = 1 - (player.bounceHeight / 20) * 0.35; // Scale from 1.0 to 0.65\n                    drawShadow(screenX, screenY + obj.size * 0.3, obj.size, shadowScale);\n                } else if (obj.type === 'campfire') {\n                    // Draw normal black drop shadow first (always present)\n                    drawShadow(screenX, screenY + obj.size * 0.3, obj.size);\n                    \n                    // Campfire yellow shadow that flickers and shrinks as fire dies (layered above black shadow)\n                    const baseScale = campfire.fireIntensity * 1.2; // 60% of current size (2x * 0.6 = 1.2x)\n                    const flicker = 0.97 + Math.sin(campfire.shadowFlicker) * 0.03; // Fluctuate between 94% and 100%\n                    const finalScale = baseScale * flicker;\n                    if (finalScale > 0) {\n                        drawShadow(screenX, screenY + obj.size * 0.3 - 10, obj.size, finalScale, 'yellow'); // Move up 10px\n                    }\n                } else if (obj.type === 'workstation') {\n                    // Draw normal shadow for workstation\n                    drawShadow(screenX, screenY + obj.size * 0.3, obj.size);\n                } else if (obj.type === 'bed') {\n                    // Draw normal shadow for bed\n                    drawShadow(screenX, screenY + obj.size * 0.3, obj.size);\n                } else if (obj.type === 'radar') {\n                    // Draw normal shadow for radar\n                    drawShadow(screenX, screenY + obj.size * 0.3, obj.size);\n                } else if (obj.type === 'firewood') {\n                    // Firewood pile shadow with collection animation\n                    let shadowSize = obj.size;\n                    let shadowY = screenY;\n                    \n                    // Apply destruction scale to shadow if firewood is being collected\n                    if (obj.destroyed && obj.destructionScale !== undefined) {\n                        shadowSize = obj.size * obj.destructionScale;\n                        // Keep shadow Y position fixed at original location\n                        if (obj.originalY !== undefined) {\n                            shadowY = obj.originalY - camera.y;\n                        }\n                    }\n                    \n                    // Only draw shadow if firewood still has some scale\n                    if (shadowSize > 0) {\n                        drawShadow(screenX, shadowY + obj.size * 0.3, shadowSize);\n                    }\n                } else if (obj.type === 'meat') {\n                    // Meat shadow with collection animation\n                    let shadowSize = obj.size;\n                    let shadowY = screenY;\n                    \n                    // Apply destruction scale to shadow if meat is being collected\n                    if (obj.destroyed && obj.destructionScale !== undefined) {\n                        shadowSize = obj.size * obj.destructionScale;\n                        // Keep shadow Y position fixed at original location\n                        if (obj.originalY !== undefined) {\n                            shadowY = obj.originalY - camera.y;\n                        }\n                    }\n                    \n                    // Only draw shadow if meat still has some scale\n                    if (shadowSize > 0) {\n                        drawShadow(screenX, shadowY + obj.size * 0.3, shadowSize);\n                    }\n                } else if (obj.type === 'poisonSpear') {\n                    // Poison spear shadow with collection animation\n                    let shadowSize = obj.size;\n                    let shadowY = screenY;\n                    \n                    // Apply destruction scale to shadow if spear is being collected\n                    if (obj.destroyed && obj.destructionScale !== undefined) {\n                        shadowSize = obj.size * obj.destructionScale;\n                    }\n                    \n                    // Only draw shadow if spear still has some scale\n                    if (shadowSize > 0) {\n                        drawShadow(screenX, shadowY + obj.size * 0.3, shadowSize);\n                    }\n                } else if (obj.type === 'wolf') {\n                    // Wolf shadow with bounce effect\n                    if (!obj.fullyDestroyed) {\n                        let shadowSize = obj.size;\n                        let shadowY = screenY;\n                        \n                        // Apply destruction scale to shadow if wolf is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            shadowSize = obj.size * obj.destructionScale;\n                            // Keep shadow Y position fixed at original location\n                            if (obj.originalY !== undefined) {\n                                shadowY = obj.originalY - camera.y;\n                            }\n                        }\n                        \n                        // Wolf shadow scales down when bouncing (same as player)\n                        const bounceHeight = obj.bounceHeight || 0;\n                        const shadowScale = (1 - (bounceHeight / 20) * 0.35) * (shadowSize / obj.size); // Combine bounce and destruction scaling\n                        \n                        // Only draw shadow if wolf still has some scale\n                        if (shadowSize > 0) {\n                            drawShadow(screenX, shadowY + obj.size * 0.3, obj.size, shadowScale);\n                        }\n                    }\n                } else if (obj.type === 'bear') {\n                    // Bear shadow with bounce effect\n                    if (!obj.fullyDestroyed) {\n                        let shadowSize = obj.size;\n                        let shadowY = screenY;\n                        \n                        // Apply destruction scale to shadow if bear is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            shadowSize = obj.size * obj.destructionScale;\n                            // Keep shadow Y position fixed at original location\n                            if (obj.originalY !== undefined) {\n                                shadowY = obj.originalY - camera.y;\n                            }\n                        }\n                        \n                        // Bear shadow scales down when bouncing (same as player)\n                        const bounceHeight = obj.bounceHeight || 0;\n                        const shadowScale = (1 - (bounceHeight / 20) * 0.35) * (shadowSize / obj.size); // Combine bounce and destruction scaling\n                        \n                        // Only draw shadow if bear still has some scale\n                        if (shadowSize > 0) {\n                            drawShadow(screenX, shadowY + obj.size * 0.3, obj.size, shadowScale);\n                        }\n                    }\n                } else if (obj.type === 'frog') {\n                    // Frog shadow with bounce effect\n                    if (!obj.fullyDestroyed) {\n                        let shadowSize = obj.size;\n                        let shadowY = screenY;\n                        \n                        // Apply destruction scale to shadow if frog is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            shadowSize = obj.size * obj.destructionScale;\n                            // Keep shadow Y position fixed at original location\n                            if (obj.originalY !== undefined) {\n                                shadowY = obj.originalY - camera.y;\n                            }\n                        }\n                        \n                        // Frog shadow scales down when bouncing (same as player)\n                        const bounceHeight = obj.bounceHeight || 0;\n                        const shadowScale = (1 - (bounceHeight / 20) * 0.35) * (shadowSize / obj.size); // Combine bounce and destruction scaling\n                        \n                        // Only draw shadow if frog still has some scale\n                        if (shadowSize > 0) {\n                            drawShadow(screenX, shadowY + obj.size * 0.3, obj.size, shadowScale);\n                        }\n                    }\n                } else if (obj.type === 'deer') {\n                    // Deer shadow with bounce effect\n                    if (!obj.fullyDestroyed) {\n                        let shadowSize = obj.size;\n                        let shadowY = screenY;\n                        \n                        // Apply destruction scale to shadow if deer is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            shadowSize = obj.size * obj.destructionScale;\n                            // Keep shadow Y position fixed at original location\n                            if (obj.originalY !== undefined) {\n                                shadowY = obj.originalY - camera.y;\n                            }\n                        }\n                        \n                        // Deer shadow scales down when bouncing (same as other creatures)\n                        const bounceHeight = obj.bounceHeight || 0;\n                        const shadowScale = (1 - (bounceHeight / 15) * 0.35) * (shadowSize / obj.size); // Use 15 instead of 20 for deer's smaller bounce\n                        \n                        // Only draw shadow if deer still has some scale\n                        if (shadowSize > 0) {\n                            drawShadow(screenX, shadowY + obj.size * 0.3, obj.size, shadowScale);\n                        }\n                    }\n                } else if (obj.type === 'minecraft_rock' || obj.type === 'minecraft_flower') {\n                    // Rock and flower shadows - only draw if not fully destroyed\n                    if (!obj.fullyDestroyed) {\n                        let shadowSize = obj.size;\n                        let shadowY = screenY;\n                        \n                        // Apply destruction scale to shadow if object is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            shadowSize = obj.size * obj.destructionScale;\n                            // Keep shadow Y position fixed at original location\n                            if (obj.originalY !== undefined) {\n                                shadowY = obj.originalY - camera.y;\n                            }\n                        }\n                        \n                        // Only draw shadow if object still has some scale\n                        if (shadowSize > 0) {\n                            drawShadow(screenX, shadowY + obj.size * 0.3, shadowSize);\n                        }\n                    }\n                } else if (obj.type === 'child') {\n                    // Child shadow with bounce effect and reduced size (60% of normal)\n                    let shadowSize = obj.size * 0.6; // 40% reduction\n                    let shadowY = screenY;\n                    \n                    // Child shadow scales down when bouncing (same as player)\n                    const bounceHeight = obj.jumpHeight || 0;\n                    const shadowScale = 1 - (bounceHeight / 20) * 0.35; // Scale from 1.0 to 0.65\n                    \n                    drawShadow(screenX, shadowY + obj.size * 0.4, shadowSize, shadowScale);\n                } else {\n                    // Only draw shadow if tree isn't fully destroyed\n                    if (!obj.fullyDestroyed) {\n                        let shadowSize = obj.size;\n                        let shadowY = screenY;\n                        \n                        // Apply destruction scale to shadow if tree is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            shadowSize = obj.size * obj.destructionScale;\n                            // Keep shadow Y position fixed at original location\n                            if (obj.originalY !== undefined) {\n                                shadowY = obj.originalY - camera.y;\n                            }\n                        }\n                        \n                        // Only draw shadow if tree still has some scale\n                        if (shadowSize > 0) {\n                            drawShadow(screenX, shadowY + obj.size * 0.3, shadowSize);\n                        }\n                    }\n                }\n            });\n            \n            // Draw objects\n            allObjects.forEach(obj => {\n                const screenX = obj.x - camera.x;\n                const screenY = obj.y - camera.y;\n                \n                if (obj.type === 'player') {\n                    // Apply bounce height (negative because up is negative Y)\n                    let bounceY = screenY - player.bounceHeight;\n                    \n                    // Add Y offset when skateboard is equipped (shift player upwards more)\n                    if (skateboardEquipped) {\n                        bounceY -= 25; // Increased from 15 to 25 pixels when on skateboard\n                    }\n                    \n                    // Draw skateboard below player if equipped\n                    if (skateboardEquipped) {\n                        const skateboardAssetId = getSkateboardAssetId(skateboardLevel);\n                        const skateboardAsset = assetCache[skateboardAssetId];\n                        if (skateboardAsset && skateboardAsset.complete) {\n                            // Draw skateboard at player's feet level (no bounce)\n                            const skateboardSize = obj.size * 0.8; // Slightly smaller than player\n                            const skateboardY = screenY + obj.size * 0.2; // Position at feet level\n                            drawAsset(skateboardAssetId, screenX, skateboardY, skateboardSize, player.facingRight);\n                        }\n                    }\n                    \n                    drawAsset(currentSkinId, screenX, bounceY, obj.size, player.facingRight);\n                    \n                    // Draw weapon in front of player (only if not on skateboard)\n                    if (!skateboardEquipped) {\n                        const weaponSize = 75; // 1.25x bigger (60 * 1.25 = 75)\n                        drawAxe(screenX, bounceY, weaponSize, player.facingRight);\n                    }\n                } else if (obj.type === 'campfire') {\n                    const campfireAssetId = assetCache['sb_campfire'] && assetCache['sb_campfire'].complete ? 'sb_campfire' : 'sb_firewood';\n                    drawAsset(campfireAssetId, screenX, screenY, obj.size * 1.4);\n                } else if (obj.type === 'workstation') {\n                    // Draw workstation using the workstation asset\n                    drawAsset('sb_workstation', screenX, screenY, obj.size);\n                } else if (obj.type === 'bed') {\n                    // Draw bed using the bed asset\n                    drawAsset('sb_bed', screenX, screenY, obj.size);\n                    \n                    // Draw children rescued text above bed\n                    const textY = screenY - obj.size/2 - 20; // 20px above bed\n                    ctx.fillStyle = 'white';\n                    ctx.strokeStyle = 'black';\n                    ctx.lineWidth = 2;\n                    ctx.font = '22px Solitreo, cursive';\n                    ctx.textAlign = 'center';\n                    \n                    const rescueText = TRANSLATIONS[currentLang].childrenRescued(bed.childrenRescued, bed.maxChildren);\n                    ctx.strokeText(rescueText, screenX, textY);\n                    ctx.fillText(rescueText, screenX, textY);\n                } else if (obj.type === 'radar') {\n                    // Draw radar using the radar asset\n                    drawAsset('sb_radar', screenX, screenY, obj.size);\n                } else if (obj.type === 'wardrobe') {\n                    // Draw wardrobe using the wardrobe asset\n                    drawAsset('sb_wardrobe', screenX, screenY, obj.size);\n                } else if (obj.type === 'firewood') {\n                    // Firewood with collection animation\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    let firewoodSize = obj.size;\n                    \n                    // Apply destruction scale if firewood is being collected\n                    if (obj.destroyed && obj.destructionScale !== undefined) {\n                        firewoodSize = obj.size * obj.destructionScale;\n                    }\n                    \n                    // Only draw if firewood still has some scale\n                    if (firewoodSize > 0) {\n                        drawAsset('sb_firewood', drawX, drawY, firewoodSize);\n                    }\n                } else if (obj.type === 'meat') {\n                    // Meat with collection animation\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    let meatSize = obj.size;\n                    \n                    // Apply destruction scale if meat is being collected\n                    if (obj.destroyed && obj.destructionScale !== undefined) {\n                        meatSize = obj.size * obj.destructionScale;\n                    }\n                    \n                    // Only draw if meat still has some scale\n                    if (meatSize > 0) {\n                        drawAsset('sb_meat', drawX, drawY, meatSize);\n                    }\n                } else if (obj.type === 'poisonSpear') {\n                    // Poison spear with collection animation\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    let spearSize = obj.size;\n                    \n                    // Apply destruction scale if spear is being collected\n                    if (obj.destroyed && obj.destructionScale !== undefined) {\n                        spearSize = obj.size * obj.destructionScale;\n                    }\n                    \n                    // Only draw if spear still has some scale\n                    if (spearSize > 0) {\n                        // Use minecraft_poison_spear asset if available\n                        let spearAssetId = null;\n                        if (assetCache['minecraft_poison_spear'] && assetCache['minecraft_poison_spear'].complete) {\n                            spearAssetId = 'minecraft_poison_spear';\n                        }\n                        \n                        if (spearAssetId) {\n                            drawAsset(spearAssetId, drawX, drawY, spearSize);\n                        } else {\n                            // Fallback: Use axe asset with green tint\n                            drawAsset('minecraft_axe', drawX, drawY, spearSize);\n                            \n                            // Add green glow effect around the spear\n                            ctx.save();\n                            ctx.globalCompositeOperation = 'screen';\n                            ctx.fillStyle = 'rgba(0, 255, 0, 0.3)';\n                            ctx.beginPath();\n                            ctx.arc(drawX, drawY, spearSize * 0.6, 0, Math.PI * 2);\n                            ctx.fill();\n                            ctx.restore();\n                        }\n                    }\n                } else if (obj.type === 'wolf') {\n                    // Wolf drawing with bounce and shake effects\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    \n                    // Apply bounce height (negative because up is negative Y)\n                    const bounceY = drawY - (obj.bounceHeight || 0);\n                    \n                    // Apply shake effect if wolf is shaking\n                    if (obj.shakeTimer > 0) {\n                        const shakeAmount = obj.shakeIntensity * (obj.shakeTimer / 0.5);\n                        drawX += (Math.random() - 0.5) * shakeAmount;\n                        drawY += (Math.random() - 0.5) * shakeAmount;\n                    }\n                    \n                    // Only draw wolf if it's not fully destroyed\n                    if (!obj.fullyDestroyed) {\n                        let wolfSize = obj.size;\n                        \n                        // Apply destruction scale if wolf is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            wolfSize = obj.size * obj.destructionScale;\n                        }\n                        \n                        // Only draw if wolf still has some scale\n                        if (wolfSize > 0) {\n                            // Flip texture when moving right, keep normal when moving left\n                            drawAsset('sb_wolf', drawX, bounceY, wolfSize, obj.movingRight);\n                        }\n                        \n                        // Draw health bar if wolf has been damaged and health bar timer is active\n                        if (obj.health < obj.maxHealth && obj.health > 0 && obj.healthBarTimer > 0) {\n                            drawTreeHealthBar(drawX, bounceY - obj.size/2 - 20, obj.health, obj.maxHealth);\n                        }\n                    }\n                } else if (obj.type === 'bear') {\n                    // Bear drawing with bounce and shake effects\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    \n                    // Apply bounce height (negative because up is negative Y)\n                    let bounceY = drawY - (obj.bounceHeight || 0);\n                    \n                    // Apply shake effect if bear is shaking\n                    if (obj.shakeTimer > 0) {\n                        const shakeAmount = obj.shakeIntensity * (obj.shakeTimer / 0.5); // Fade shake over time\n                        drawX += (Math.random() - 0.5) * shakeAmount;\n                        bounceY += (Math.random() - 0.5) * shakeAmount;\n                    }\n                    \n                    // Only draw bear if it's not fully destroyed\n                    if (!obj.fullyDestroyed) {\n                        let bearSize = obj.size;\n                        \n                        // Apply destruction scale if bear is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            bearSize = obj.size * obj.destructionScale;\n                        }\n                        \n                        // Only draw if bear still has some scale\n                        if (bearSize > 0) {\n                            // Flip texture when moving right, keep normal when moving left\n                            drawAsset('sb_bear', drawX, bounceY, bearSize, obj.movingRight);\n                        }\n                        \n                        // Draw health bar if bear has been damaged and health bar timer is active\n                        if (obj.health < obj.maxHealth && obj.health > 0 && obj.healthBarTimer > 0) {\n                            drawTreeHealthBar(drawX, bounceY - obj.size/2 - 20, obj.health, obj.maxHealth);\n                        }\n                    }\n                } else if (obj.type === 'frog') {\n                    // Frog drawing with bounce and shake effects\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    \n                    // Apply bounce height (negative because up is negative Y)\n                    const bounceY = drawY - (obj.bounceHeight || 0);\n                    \n                    // Apply shake effect if frog is shaking\n                    if (obj.shakeTimer > 0) {\n                        const shakeAmount = obj.shakeIntensity * (obj.shakeTimer / 0.5);\n                        drawX += (Math.random() - 0.5) * shakeAmount;\n                        drawY += (Math.random() - 0.5) * shakeAmount;\n                    }\n                    \n                    // Only draw frog if it's not fully destroyed\n                    if (!obj.fullyDestroyed) {\n                        let frogSize = obj.size;\n                        \n                        // Apply destruction scale if frog is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            frogSize = obj.size * obj.destructionScale;\n                        }\n                        \n                        // Only draw if frog still has some scale\n                        if (frogSize > 0) {\n                            // Flip texture when moving right, keep normal when moving left\n                            drawAsset('sb_frog', drawX, bounceY, frogSize, obj.movingRight);\n                        }\n                        \n                        // Draw health bar if frog has been damaged and health bar timer is active\n                        if (obj.health < obj.maxHealth && obj.health > 0 && obj.healthBarTimer > 0) {\n                            drawTreeHealthBar(drawX, bounceY - obj.size/2 - 20, obj.health, obj.maxHealth);\n                        }\n                    }\n                } else if (obj.type === 'deer') {\n                    // Deer drawing with bounce and shake effects\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    \n                    // Apply bounce height (negative because up is negative Y)\n                    const bounceY = drawY - (obj.bounceHeight || 0);\n                    \n                    // Apply shake effect if deer is shaking\n                    if (obj.shakeTimer > 0) {\n                        const shakeAmount = obj.shakeIntensity * (obj.shakeTimer / 0.5);\n                        drawX += (Math.random() - 0.5) * shakeAmount;\n                        drawY += (Math.random() - 0.5) * shakeAmount;\n                    }\n                    \n                    // Only draw deer if it's not fully destroyed\n                    if (!obj.fullyDestroyed) {\n                        let deerSize = obj.size;\n                        \n                        // Apply destruction scale if deer is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            deerSize = obj.size * obj.destructionScale;\n                        }\n                        \n                        // Only draw if deer still has some scale\n                        if (deerSize > 0) {\n                            // Scale down by 20% from the doubled size (2x * 0.8 = 1.6x larger appearance)\n                            const visualSize = deerSize * 2 * 0.8;\n                            \n                            // Add vertical offset to align feet with shadow (move artwork up)\n                            const verticalOffset = -40; // Move deer artwork up by 40 pixels\n                            \n                            // Determine which asset to use based on deer state (demonic takes priority over hungry)\n                            let deerAssetId = 'horror_deer';\n                            if (obj.isDemonic && assetCache['horror_deer_demonic'] && assetCache['horror_deer_demonic'].complete) {\n                                deerAssetId = 'horror_deer_demonic';\n                            } else if (obj.isHungry && assetCache['horror_deer_hungry'] && assetCache['horror_deer_hungry'].complete) {\n                                deerAssetId = 'horror_deer_hungry';\n                            }\n                            \n                            // Use appropriate deer asset if available, otherwise fallback to wolf with darker tint\n                            if (assetCache[deerAssetId] && assetCache[deerAssetId].complete) {\n                                // Flip texture when moving right, keep normal when moving left\n                                drawAsset(deerAssetId, drawX, bounceY + verticalOffset, visualSize, obj.movingRight);\n                            } else if (assetCache['horror_deer'] && assetCache['horror_deer'].complete) {\n                                // Fallback to regular deer if hungry deer asset not available\n                                drawAsset('horror_deer', drawX, bounceY + verticalOffset, visualSize, obj.movingRight);\n                            } else {\n                                // Final fallback: Use wolf asset with dark tint\n                                ctx.save();\n                                ctx.filter = 'brightness(0.3) contrast(2)'; // Make it very dark\n                                drawAsset('sb_wolf', drawX, bounceY + verticalOffset, visualSize, obj.movingRight);\n                                ctx.restore();\n                            }\n                        }\n                        \n                        // Draw health bar if deer has been damaged and health bar timer is active\n                        if (obj.health < obj.maxHealth && obj.health > 0 && obj.healthBarTimer > 0) {\n                            drawTreeHealthBar(drawX, bounceY - obj.size/2 - 20, obj.health, obj.maxHealth);\n                        }\n                    }\n                } else if (obj.type === 'child') {\n                    // Child drawing with bounce effect\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    \n                    // Apply bounce effect (jump animation like other entities)\n                    let bounceY = drawY - (obj.jumpHeight || 0);\n                    \n                    // Draw the child asset\n                    drawAsset(obj.assetId, drawX, bounceY, obj.size, obj.movingRight);\n                } else if (obj.type === 'minecraft_rock' || obj.type === 'minecraft_flower') {\n                    // Rock and flower drawing with shake effect\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    \n                    // Apply shake effect if object is shaking\n                    if (obj.shakeTimer > 0) {\n                        const shakeAmount = obj.shakeIntensity * (obj.shakeTimer / 0.5); // Fade shake over time\n                        drawX += (Math.random() - 0.5) * shakeAmount;\n                        drawY += (Math.random() - 0.5) * shakeAmount;\n                    }\n                    \n                    // Only draw object if it's not fully destroyed\n                    if (!obj.fullyDestroyed) {\n                        let objSize = obj.size;\n                        \n                        // Apply destruction scale if object is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            objSize = obj.size * obj.destructionScale;\n                        }\n                        \n                        // Only draw if object still has some scale\n                        if (objSize > 0) {\n                            drawAsset(obj.type, drawX, drawY, objSize);\n                        }\n                        \n                        // Draw health bar if object has been damaged and health bar timer is active\n                        if (obj.health < obj.maxHealth && obj.health > 0 && obj.healthBarTimer > 0) {\n                            drawTreeHealthBar(drawX, drawY - obj.size/2 - 20, obj.health, obj.maxHealth);\n                        }\n                    }\n                } else {\n                    // Tree drawing with shake effect\n                    let drawX = screenX;\n                    let drawY = screenY;\n                    \n                    // Apply shake effect if tree is shaking\n                    if (obj.shakeTimer > 0) {\n                        const shakeAmount = obj.shakeIntensity * (obj.shakeTimer / 0.5); // Fade shake over time\n                        drawX += (Math.random() - 0.5) * shakeAmount;\n                        drawY += (Math.random() - 0.5) * shakeAmount;\n                    }\n                    \n                    // Only draw tree if it's not fully destroyed\n                    if (!obj.fullyDestroyed) {\n                        let treeSize = obj.size;\n                        \n                        // Apply destruction scale if tree is being destroyed\n                        if (obj.destroyed && obj.destructionScale !== undefined) {\n                            treeSize = obj.size * obj.destructionScale;\n                        }\n                        \n                        // Only draw if tree still has some scale\n                        if (treeSize > 0) {\n                            drawAsset(obj.type, drawX, drawY, treeSize);\n                        }\n                        \n                        // Draw health bar if tree has been damaged and health bar timer is active\n                        if (obj.health < obj.maxHealth && obj.health > 0 && obj.healthBarTimer > 0) {\n                            drawTreeHealthBar(drawX, drawY - obj.size/2 - 20, obj.health, obj.maxHealth);\n                        }\n                    }\n                }\n            });\n            \n            // Draw object labels above all objects (second pass so labels are always on top)\n            allObjects.forEach(obj => {\n                if (obj.type === 'player' || obj.type === 'child') return;\n                if (obj.fullyDestroyed) return;\n                if (obj.destroyed) return;\n                const label = getObjectLabelText(obj);\n                if (!label) return;\n                const screenX = obj.x - camera.x;\n                const screenY = obj.y - camera.y - (obj.size / 2) - 10;\n                drawObjectLabel(screenX, screenY, label);\n            });\n\n            // Draw wood transfer animations\n            woodTransfers.forEach(transfer => {\n                if (transfer.currentX !== undefined && transfer.currentY !== undefined) {\n                    const screenX = transfer.currentX - camera.x;\n                    const screenY = transfer.currentY - camera.y;\n                    \n                    // Draw wood pile\n                    const firewoodAsset = assetCache['sb_firewood'];\n                    if (firewoodAsset && firewoodAsset.complete) {\n                        ctx.save();\n                        ctx.globalAlpha = 0.9;\n                        drawAsset('sb_firewood', screenX, screenY, transfer.currentSize);\n                        ctx.restore();\n                    }\n                }\n            });\n            \n            // Draw meat transfer animations\n            meatTransfers.forEach(transfer => {\n                const screenX = transfer.currentX - camera.x;\n                const screenY = transfer.currentY - camera.y;\n                \n                // Draw meat using the same pattern as wood\n                ctx.save();\n                ctx.globalAlpha = 0.9;\n                drawAsset('sb_meat', screenX, screenY, transfer.currentSize);\n                ctx.restore();\n            });\n            \n            // Draw particles on top\n            drawParticles();\n            \n            // Edit mode visual effects\n            if (gameMode === 'edit') {\n                ctx.fillStyle = 'rgba(255, 255, 0, 0.3)';\n                const editX = player.x - camera.x - player.size/2;\n                const editY = player.y - camera.y - player.size/2 - player.bounceHeight;\n                ctx.fillRect(editX, editY, player.size, player.size);\n            }\n            \n            // Draw campfire indicator when off-screen\n            drawCampfireIndicator();\n            \n            // Draw help bubble for nearby children\n            drawHelpBubble();\n        }\n        \n        function updatePlayerCoordinates() {\n            const coordinatesElement = document.getElementById('playerCoordinates');\n            if (coordinatesElement) {\n                coordinatesElement.textContent = `X: ${Math.round(player.x)}, Y: ${Math.round(player.y)}`;\n            }\n        }\n        \n        function updatePlayerCoordinatesVisibility() {\n            const coordinatesElement = document.getElementById('playerCoordinates');\n            if (coordinatesElement) {\n                const shouldShow = window.gameConfig.ui.showPlayerPosition !== false; // Default to true\n                coordinatesElement.style.display = shouldShow ? 'block' : 'none';\n            }\n        }\n        \n        function gameLoop(currentTime) {\n            const deltaTime = Math.min((currentTime - lastTime) / 1000, 0.05); // Cap at 20fps minimum\n            lastTime = currentTime;\n            \n            updatePlayer(deltaTime);\n            updateAxe(deltaTime);\n            checkAxeCollisions();\n            checkGenericEnemyCollisions('wolf');\n            checkGenericEnemyCollisions('bear');\n            checkFrogCollisions();\n            checkDeerCollisions();\n            updateTrees(deltaTime);\n            updateRocksAndFlowers(deltaTime);\n            updateAllParticles(deltaTime);\n            updateFirewoodPiles(deltaTime);\n            updateMeatPiles(deltaTime);\n            updatePoisonSpears(deltaTime);\n            updateGenericEnemies('wolf', deltaTime);\n            updateGenericEnemies('bear', deltaTime);\n            updateFrogs(deltaTime);\n            updateDeer(deltaTime);\n            updateChildren(deltaTime);\n            updateCamera(deltaTime);\n            updateCampfire(deltaTime);\n            updateWoodTransfers(deltaTime);\n            updateMeatTransfers(deltaTime);\n            updateCraftingArrow(deltaTime);\n            updateDayNightCycle(deltaTime);\n            updateMessages(deltaTime);\n            updateMinimap();\n            updateXPBarVisibility();\n            updateCraftButtonVisibility();\n            updateWardrobeButtonVisibility();\n            updatePlayerCoordinates();\n            // Update game timer (only after first wood picked up and not in intro)\n            if (firstWoodPickedUp && !introScreenActive) {\n                gameTimer += deltaTime;\n                updateGameTimerDisplay();\n            }\n            render();\n            drawCraftingArrow();\n            drawFirstTreeArrow();\n            drawCampfireArrow();\n            \n            // Only continue game loop if game is running\n            if (isGameRunning) {\n                requestAnimationFrame(gameLoop);\n            }\n        }\n        \n        function setupInput() {\n            // Resume AudioContext on user interaction\n            const resumeAudio = () => {\n                const ctx = getAudioContext();\n                if (ctx.state === 'suspended') ctx.resume();\n                if (!bgMusicPlaying) {\n                    if (audioBuffers['bg_forest_music']) {\n                        startBackgroundMusic();\n                    } else {\n                        window.shouldPlayBgMusic = true;\n                    }\n                }\n            };\n            ['touchstart', 'mousedown', 'keydown'].forEach(evt => {\n                document.addEventListener(evt, resumeAudio, { passive: true });\n            });\n\n            // Keyboard input\n            document.addEventListener('keydown', (e) => {\n                input.keys[e.code] = true;\n                \n                // Spacebar triggers axe swing (only if not on skateboard)\n                if (e.code === 'Space' && !axe.isSwinging && !skateboardEquipped) {\n                    axe.isSwinging = true;\n                    axe.swingTimer = 0;\n                    axe.hasHitThisSwing = false; // Reset hit flag for new swing\n                }\n                \n                e.preventDefault();\n            });\n            \n            document.addEventListener('keyup', (e) => {\n                input.keys[e.code] = false;\n                e.preventDefault();\n            });\n            \n            // Touch input with virtual joystick (from Last Stand)\n            canvas.addEventListener('touchstart', (e) => {\n                // Check if the touch is on an inventory slot\n                const touch = e.touches[0];\n                const element = document.elementFromPoint(touch.clientX, touch.clientY);\n                \n                // If touching an inventory slot, let it handle the event\n                if (element && element.classList && element.classList.contains('inventorySlot')) {\n                    return; // Don't prevent default, let inventory handle it\n                }\n                \n                e.preventDefault();\n                \n                // Create joystick at touch position only if not already active\n                if (!joystickActive) {\n                    createJoystick(touch.clientX, touch.clientY, touch.identifier);\n                    createTouchFeedback(touch.clientX, touch.clientY);\n                }\n            });\n            \n            canvas.addEventListener('touchmove', (e) => {\n                e.preventDefault();\n                if (joystickActive) {\n                    handleJoystickMove(e);\n                }\n            });\n            \n            canvas.addEventListener('touchend', (e) => {\n                e.preventDefault();\n                handleJoystickEnd(e);\n            });\n            \n            canvas.addEventListener('touchcancel', (e) => {\n                e.preventDefault();\n                handleJoystickEnd(e);\n            });\n            \n            // Mouse input (for desktop)\n            canvas.addEventListener('mousedown', (e) => {\n                const rect = canvas.getBoundingClientRect();\n                const x = e.clientX - rect.left;\n                const y = e.clientY - rect.top;\n                \n                input.mouse.active = true;\n                input.mouse.x = x;\n                input.mouse.y = y;\n                \n                createTouchFeedback(x, y);\n            });\n            \n            canvas.addEventListener('mousemove', (e) => {\n                if (!input.mouse.active) return;\n                const rect = canvas.getBoundingClientRect();\n                input.mouse.x = e.clientX - rect.left;\n                input.mouse.y = e.clientY - rect.top;\n            });\n            \n            canvas.addEventListener('mouseup', () => {\n                input.mouse.active = false;\n            });\n            \n            // Edit mode tree placement\n            if (gameMode === 'edit') {\n                canvas.addEventListener('click', (e) => {\n                    const rect = canvas.getBoundingClientRect();\n                    const worldX = (e.clientX - rect.left) + camera.x;\n                    const worldY = (e.clientY - rect.top) + camera.y;\n                    \n                    // Add tree at clicked position\n                    const gridX = Math.floor(worldX / GRID_SIZE);\n                    const gridY = Math.floor(worldY / GRID_SIZE);\n                    const gridKey = `${gridX},${gridY}`;\n                    \n                    if (!trees.has(gridKey)) {\n                        trees.set(gridKey, []);\n                    }\n                    \n                    const gridTrees = trees.get(gridKey);\n                    const randomType = TREE_TYPES[Math.floor(Math.random() * TREE_TYPES.length)];\n                    gridTrees.push({ \n                        x: worldX, y: worldY, type: randomType, size: 400,\n                        health: 10, maxHealth: 10, shakeTimer: 0, shakeIntensity: 0, \n                        healthBarTimer: 0, particles: []\n                    });\n                });\n            }\n        }\n        \n        function preloadAssets(callback) {\n            let loadedCount = 0;\n\n            preloadAssetIds.forEach(id => {\n                const assetInfo = lib.getAsset(id);\n                if (assetInfo) {\n                    const img = new Image();\n                    img.onload = () => {\n                        loadedCount++;\n                        if (loadedCount === preloadAssetIds.length) {\n                            callback();\n                        }\n                    };\n                    img.onerror = () => {\n                        loadedCount++;\n                        if (loadedCount === preloadAssetIds.length) {\n                            callback();\n                        }\n                    };\n                    img.src = assetInfo.url;\n                    assetCache[id] = img;\n                } else {\n                    loadedCount++;\n                    if (loadedCount === preloadAssetIds.length) {\n                        callback();\n                    }\n                }\n            });\n        }\n\n        function lateLoadAssets(callback) {\n            let loadedCount = 0;\n\n            lateLoadAssetIds.forEach(id => {\n                const assetInfo = lib.getAsset(id);\n                if (assetInfo) {\n                    const img = new Image();\n                    img.onload = () => {\n                        loadedCount++;\n                        if (loadedCount === lateLoadAssetIds.length) {\n                            lateAssetsLoaded = true;\n                            callback();\n                        }\n                    };\n                    img.onerror = () => {\n                        loadedCount++;\n                        if (loadedCount === lateLoadAssetIds.length) {\n                            lateAssetsLoaded = true;\n                            callback();\n                        }\n                    };\n                    img.src = assetInfo.url;\n                    assetCache[id] = img;\n                } else {\n                    loadedCount++;\n                    if (loadedCount === lateLoadAssetIds.length) {\n                        lateAssetsLoaded = true;\n                        callback();\n                    }\n                }\n            });\n        }\n        \n        function hideIntroScreen() {\n            const introScreen = document.getElementById('introScreen');\n            if (introScreen) {\n                introScreen.classList.add('fade-out');\n                setTimeout(() => {\n                    introScreen.style.display = 'none';\n                    introScreenActive = false; // Mark intro as complete\n                }, 600); // Wait for fade transition to complete (40% faster)\n            } else {\n                introScreenActive = false; // No intro screen, mark as complete\n            }\n        }\n        \n        function initializeGame() {\n            canvas = document.getElementById('gameCanvas');\n            ctx = canvas.getContext('2d');\n            \n            // Set canvas size\n            canvas.width = 720;\n            canvas.height = 1280;\n            \n            // Initialize crafting dialog handlers\n            const craftButton = document.getElementById('craftButton');\n            const craftingDialog = document.getElementById('craftingDialog');\n            const craftingBackdrop = document.getElementById('craftingBackdrop');\n            const craftingCloseButton = document.getElementById('craftingCloseButton');\n            \n            function openCraftingDialog() {\n                // Only open if craft button is visible (player is near workstation)\n                if (!craftButton || !craftButton.classList.contains('visible')) {\n                    return;\n                }\n                \n                if (craftingDialog && craftingBackdrop) {\n                    // Clear all movement input to prevent continued movement\n                    input.keys = {};\n                    input.mouse.active = false;\n                    if (window.joystickActive) {\n                        window.joystickActive = false;\n                        if (window.joystickInput) {\n                            window.joystickInput.x = 0;\n                            window.joystickInput.y = 0;\n                        }\n                    }\n                    \n                    craftingDialog.classList.add('visible');\n                    craftingBackdrop.classList.add('visible');\n                    \n                    // Hide the red arrow once craft button is clicked\n                    craftingArrow.hidden = true;\n                    if (campfire.level < 4) {\n                        craftingArrow.revealAgainAtLevel4 = true;\n                    }\n                    \n                    updateCraftingButtonStates();\n                    updateCraftingIcons();\n                    updateCraftingCosts();\n                }\n            }\n            \n            function closeCraftingDialog() {\n                if (craftingDialog && craftingBackdrop) {\n                    craftingDialog.classList.remove('visible');\n                    craftingBackdrop.classList.remove('visible');\n                }\n            }\n            \n            if (craftButton) {\n                craftButton.addEventListener('click', openCraftingDialog);\n            }\n            \n            if (craftingCloseButton) {\n                craftingCloseButton.addEventListener('click', closeCraftingDialog);\n            }\n            \n            if (craftingBackdrop) {\n                craftingBackdrop.addEventListener('click', closeCraftingDialog);\n            }\n            \n            // Initialize wardrobe dialog handlers\n            const wardrobeButton = document.getElementById('wardrobeButton');\n            const wardrobeDialog = document.getElementById('wardrobeDialog');\n            const wardrobeBackdrop = document.getElementById('wardrobeBackdrop');\n            const wardrobeCloseButton = document.getElementById('wardrobeCloseButton');\n            const skinGrid = document.getElementById('skinGrid');\n            \n            function openWardrobeDialog() {\n                // Only open if wardrobe button is visible (player is near wardrobe)\n                if (!wardrobeButton || !wardrobeButton.classList.contains('visible')) {\n                    return;\n                }\n                \n                if (wardrobeDialog && wardrobeBackdrop) {\n                    // Clear all movement input to prevent continued movement\n                    input.keys = {};\n                    input.mouse.active = false;\n                    if (window.joystickActive) {\n                        window.joystickActive = false;\n                        if (window.joystickInput) {\n                            window.joystickInput.x = 0;\n                            window.joystickInput.y = 0;\n                        }\n                    }\n                    \n                    wardrobeDialog.classList.add('visible');\n                    wardrobeBackdrop.classList.add('visible');\n                    \n                    // Populate skin grid\n                    populateSkinGrid();\n                }\n            }\n            \n            function closeWardrobeDialog() {\n                if (wardrobeDialog && wardrobeBackdrop) {\n                    wardrobeDialog.classList.remove('visible');\n                    wardrobeBackdrop.classList.remove('visible');\n                }\n            }\n            \n            function populateSkinGrid() {\n                if (!skinGrid) return;\n                skinGrid.innerHTML = ''; // Clear existing options\n                \n                AVAILABLE_SKINS.forEach(skin => {\n                    const skinOption = document.createElement('div');\n                    skinOption.className = 'skinOption' + (currentSkinId === skin.id ? ' selected' : '');\n                    \n                    // Create preview image\n                    const preview = document.createElement('img');\n                    preview.className = 'skinPreview';\n                    const assetInfo = lib.getAsset(skin.id);\n                    if (assetInfo) {\n                        preview.src = assetInfo.url;\n                    }\n                    \n                    // Create name label\n                    const nameLabel = document.createElement('div');\n                    nameLabel.className = 'skinName';\n                    nameLabel.textContent = skin.name;\n                    \n                    // Add click handler\n                    skinOption.addEventListener('click', () => {\n                        currentSkinId = skin.id;\n                        // Update all skin options to show selection\n                        document.querySelectorAll('.skinOption').forEach(option => {\n                            option.classList.remove('selected');\n                        });\n                        skinOption.classList.add('selected');\n                        \n                        // Save to gameConfig\n                        if (!window.gameConfig.inventory) {\n                            window.gameConfig.inventory = {};\n                        }\n                        window.gameConfig.inventory.currentSkinId = currentSkinId;\n                    });\n                    \n                    skinOption.appendChild(preview);\n                    skinOption.appendChild(nameLabel);\n                    skinGrid.appendChild(skinOption);\n                });\n            }\n            \n            if (wardrobeButton) {\n                wardrobeButton.addEventListener('click', openWardrobeDialog);\n            }\n            \n            if (wardrobeCloseButton) {\n                wardrobeCloseButton.addEventListener('click', closeWardrobeDialog);\n            }\n            \n            if (wardrobeBackdrop) {\n                wardrobeBackdrop.addEventListener('click', closeWardrobeDialog);\n            }\n            \n            // Initialize upgrade buttons\n            const upgradeGoodAxeBtn = document.getElementById('upgradeGoodAxe');\n            const upgradeStrongAxeBtn = document.getElementById('upgradeStrongAxe');\n            \n            if (upgradeGoodAxeBtn) {\n                upgradeGoodAxeBtn.addEventListener('click', () => { playSound('sfx_craft', 0.7); upgradeAxe('good'); });\n            }\n            \n            if (upgradeStrongAxeBtn) {\n                upgradeStrongAxeBtn.addEventListener('click', () => { playSound('sfx_craft', 0.7); upgradeAxe('strong'); });\n            }\n            \n            // Add skateboard upgrade button listeners\n            const upgradeBasicSkateboardBtn = document.getElementById('upgradeBasicSkateboard');\n            const upgradeFastSkateboardBtn = document.getElementById('upgradeFastSkateboard');\n            const upgradeSuperSkateboardBtn = document.getElementById('upgradeSuperSkateboard');\n            \n            if (upgradeBasicSkateboardBtn) {\n                upgradeBasicSkateboardBtn.addEventListener('click', () => { playSound('sfx_craft', 0.7); upgradeSkateboard(1); });\n            }\n            \n            if (upgradeFastSkateboardBtn) {\n                upgradeFastSkateboardBtn.addEventListener('click', () => { playSound('sfx_craft', 0.7); upgradeSkateboard(2); });\n            }\n            \n            if (upgradeSuperSkateboardBtn) {\n                upgradeSuperSkateboardBtn.addEventListener('click', () => { playSound('sfx_craft', 0.7); upgradeSkateboard(3); });\n            }\n            \n            // Add spear upgrade button listeners\n            const upgradeBasicSpearBtn = document.getElementById('upgradeBasicSpear');\n            const upgradeSharpSpearBtn = document.getElementById('upgradeSharpSpear');\n            const upgradePoisonSpearBtn = document.getElementById('upgradePoisonSpear');\n            \n            if (upgradeBasicSpearBtn) {\n                upgradeBasicSpearBtn.addEventListener('click', () => { playSound('sfx_craft', 0.7); upgradeSpear(1); });\n            }\n            \n            if (upgradeSharpSpearBtn) {\n                upgradeSharpSpearBtn.addEventListener('click', () => { playSound('sfx_craft', 0.7); upgradeSpear(2); });\n            }\n            \n            if (upgradePoisonSpearBtn) {\n                upgradePoisonSpearBtn.addEventListener('click', () => { playSound('sfx_craft', 0.7); upgradeSpear(3); });\n            }\n            \n            // Initialize crafting icons and costs\n            updateCraftingIcons();\n            updateCraftingCosts();\n            \n            // Wire up language toggle button\n            const langToggleBtn = document.getElementById('langToggleBtn');\n            if (langToggleBtn) {\n                langToggleBtn.addEventListener('click', toggleLanguage);\n            }\n\n            // Wire up leaderboard button\n            const leaderboardBtn = document.getElementById('leaderboardBtn');\n            const leaderboardBackdrop = document.getElementById('leaderboardBackdrop');\n            const leaderboardModal = document.getElementById('leaderboardModal');\n            const leaderboardCloseBtn = document.getElementById('leaderboardCloseBtn');\n\n            async function showLeaderboard() {\n                if (!leaderboardModal || !leaderboardBackdrop) return;\n                leaderboardModal.classList.add('visible');\n                leaderboardBackdrop.classList.add('visible');\n                const listEl = document.getElementById('leaderboardList');\n                listEl.innerHTML = '<div class=\"leaderboardEmpty\">\u062c\u0627\u0631\u064a \u0627\u0644\u062a\u062d\u0645\u064a\u0644...</div>';\n                try {\n                    const entries = await lib.getTopNEntriesFromLeaderboard(10);\n                    if (!entries || entries.length === 0) {\n                        listEl.innerHTML = '<div class=\"leaderboardEmpty\">\u0644\u0627 \u064a\u0648\u062c\u062f \u0644\u0627\u0639\u0628\u0648\u0646 \u0628\u0639\u062f!</div>';\n                        return;\n                    }\n                    listEl.innerHTML = '';\n                    const medals = ['\ud83e\udd47','\ud83e\udd48','\ud83e\udd49'];\n                    entries.forEach((entry, i) => {\n                        const row = document.createElement('div');\n                        row.className = 'leaderboardRow' + (i===0?' top1':i===1?' top2':i===2?' top3':'');\n                        const rank = document.createElement('div');\n                        rank.className = 'leaderboardRank';\n                        rank.textContent = medals[i] || (i+1)+'.';\n                        const name = document.createElement('div');\n                        name.className = 'leaderboardName';\n                        name.textContent = entry.playerName || ('\u0644\u0627\u0639\u0628 '+(i+1));\n                        const timeEl = document.createElement('div');\n                        timeEl.className = 'leaderboardTime';\n                        const secs = Math.max(0, 999999 - (entry.score || 0));\n                        timeEl.textContent = formatTime(secs);\n                        row.appendChild(rank); row.appendChild(name); row.appendChild(timeEl);\n                        listEl.appendChild(row);\n                    });\n                } catch(e) {\n                    listEl.innerHTML = '<div class=\"leaderboardEmpty\">\u062a\u0639\u0630\u0631 \u062a\u062d\u0645\u064a\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a</div>';\n                }\n            }\n\n            function hideLeaderboard() {\n                if (leaderboardModal) leaderboardModal.classList.remove('visible');\n                if (leaderboardBackdrop) leaderboardBackdrop.classList.remove('visible');\n            }\n\n            if (leaderboardBtn) leaderboardBtn.addEventListener('click', showLeaderboard);\n            if (leaderboardCloseBtn) leaderboardCloseBtn.addEventListener('click', hideLeaderboard);\n            if (leaderboardBackdrop) leaderboardBackdrop.addEventListener('click', hideLeaderboard);\n\n            // Initialize player position from gameConfig\n            player.x = window.gameConfig.player.startX;\n            player.y = window.gameConfig.player.startY;\n            player.targetX = player.x;\n            player.targetY = player.y;\n            \n            // Initialize camera\n            camera.x = player.x - canvas.width / 2;\n            camera.y = player.y - canvas.height / 2;\n            \n            // No temporary deer - deer will spawn naturally during night of day 5\n            \n            // Initialize inventory from gameConfig\n            if (!window.gameConfig.inventory) {\n                window.gameConfig.inventory = { firewood: 0, meat: 0, hasPoisonSpear: false, hasSkateBoard: true, skateboardEquipped: false, currentSkinId: 'spongebob_skin' };\n            }\n            \n            // Player has no XP system anymore - only campfire has XP\n            if (!window.gameConfig.frogsKilled) {\n                window.gameConfig.frogsKilled = 0;\n            }\n            if (!window.gameConfig.poisonSpearSpawned) {\n                window.gameConfig.poisonSpearSpawned = false;\n            }\n            if (!window.gameConfig.firstFrogSpawned) {\n                window.gameConfig.firstFrogSpawned = false;\n            }\n            if (window.gameConfig.inventory.firewood) {\n                firewoodCount = window.gameConfig.inventory.firewood;\n            }\n            if (window.gameConfig.inventory.meat) {\n                meatCount = window.gameConfig.inventory.meat;\n            }\n            if (window.gameConfig.inventory.hasSpear) {\n                hasSpear = window.gameConfig.inventory.hasSpear;\n            }\n            if (window.gameConfig.inventory.spearLevel) {\n                spearLevel = window.gameConfig.inventory.spearLevel;\n            }\n            if (window.gameConfig.inventory.currentWeapon) {\n                currentWeapon = window.gameConfig.inventory.currentWeapon;\n            }\n            if (window.gameConfig.inventory.hasSkateBoard !== undefined) {\n                hasSkateBoard = window.gameConfig.inventory.hasSkateBoard;\n            }\n            if (window.gameConfig.inventory.skateboardEquipped !== undefined) {\n                skateboardEquipped = window.gameConfig.inventory.skateboardEquipped;\n            }\n            if (window.gameConfig.inventory.currentSkinId) {\n                currentSkinId = window.gameConfig.inventory.currentSkinId;\n            } else {\n                currentSkinId = 'spongebob_skin'; // Default to SpongeBob\n            }\n            \n            // Update UI\n            { const t = TRANSLATIONS[currentLang]; document.getElementById('dayCounter').textContent = currentLang === 'ar' ? `${t.day} ${window.gameConfig.ui.day}` : `Day ${window.gameConfig.ui.day}`; }\n            \n            // Initialize weapon inventory display\n            updateWeaponInventory();\n            \n            // Initialize skateboard inventory display\n            updateSkateboardInventory();\n            \n            // Initialize firewood inventory display\n            updateFirewoodInventory();\n            \n            // Initialize meat inventory display\n            updateMeatInventory();\n            \n            // Initialize health bar\n            updateHealthBar();\n            \n            // Initialize hunger bar\n            updateHungerBar();\n            \n            // Initialize fire bar\n            updateFireBar();\n            \n            // Initialize XP bar\n            updateXPBar();\n            \n            // Initialize player coordinates visibility\n            updatePlayerCoordinatesVisibility();\n            \n            // Initialize deer despawn flag\n            window.deerDespawnedToday = false;\n            \n            // No temporary deer - deer will spawn naturally during night of day 1\n\n            // Children will be initialized after late assets are loaded\n            \n            \n            // Initialize player speed tracking\n            player.lastX = player.x;\n            player.lastY = player.y;\n            player.currentSpeed = 0;\n            \n            // Initialize victory tracking\n            window.victoryTriggered = false;\n            \n            // Initialize radar based on campfire level\n            if (campfire.level >= 5) {\n                radar.enabled = true;\n            }\n            \n            setupInput();\n            window.shouldPlayBgMusic = true;\n            loadAudioAssets();\n            requestAnimationFrame(gameLoop);\n        }\n        \n        // =====================\n        // LANGUAGE / TRANSLATION SYSTEM\n        // =====================\n        let currentLang = 'ar';\n\n        const TRANSLATIONS = {\n            en: {\n                langBtn: '\u0627\u0644\u0639\u0631\u0628\u064a\u0629',\n                craft: 'Open',\n                wardrobe: 'Open',\n                done: 'Done',\n                craftUpgrade: 'Craft & Upgrade',\n                chooseSkin: 'Choose Your Skin',\n                health: 'Health',\n                hunger: 'Hunger',\n                fire: 'Fire',\n                day: 'Day',\n                settingsName: 'SpongeBob Settings',\n                oldAxe: 'Old Axe',\n                goodAxe: 'Good Axe',\n                strongAxe: 'Strong Axe',\n                basicSpear: 'Basic Spear',\n                sharpSpear: 'Sharp Spear',\n                poisonSpear: 'Poison Spear',\n                skateboard: 'Skateboard',\n                fastboard: 'Fastboard',\n                superboard: 'Superboard',\n                owned: 'Owned',\n                introText: \"SpongeBob!<br>Nights in Bikini Bottom\",\n                // Game messages\n                nightApproaching: 'Night is approaching',\n                nightApproachingHungry: 'Night is approaching, the deer is hungry',\n                nightApproachingDemonic: 'Night is approaching, the deer is demonic tonight',\n                campfireAlmostOut: 'The campfire is almost out',\n                cookMeat: 'Mmmm... cooked meat!',\n                notEnoughWood: 'Not enough wood!',\n                campfireProtects: 'The Campfire protects you from monsters',\n                campfireLevel: (n) => `Campfire reached Level ${n}!`,\n                newUpgrades: 'New upgrades available at the workstation!',\n                radarActivated: 'Radar station activated!',\n                survived99: \"I'm ready! You survived 99 nights in Bikini Bottom!\",\n                maxCampfireLevel: 'Max campfire level',\n                levelProgress: (l, x, m) => `Level ${l} progress: ${x}/${m}`,\n                childrenRescued: (n, m) => `${n} of ${m} children rescued`,\n                gameOver: 'Oh Tartar Sauce! Try Again!',\n\n                tryAgain: 'Try Again',\n                allRescued: (d) => `All children rescued<br>in ${d} days!`,\n                keepPlaying: 'Keep Playing',\n                ateMultipleMeat: (n) => `Ate ${n} pieces of cooked meat!`,\n                requiresCampfire: (n) => `Requires\\nLevel ${n}\\nCampfire`\n            },\n            ar: {\n                langBtn: 'English',\n                craft: '\u0641\u062a\u062d',\n                wardrobe: '\u0641\u062a\u062d',\n                done: '\u062a\u0645',\n                craftUpgrade: '\u0635\u0646\u0639 \u0648\u062a\u0631\u0642\u064a\u0629',\n                chooseSkin: '\u0627\u062e\u062a\u0631 \u0645\u0638\u0647\u0631\u0643',\n                health: '\u0627\u0644\u0635\u062d\u0629',\n                hunger: '\u0627\u0644\u062c\u0648\u0639',\n                fire: '\u0627\u0644\u0646\u0627\u0631',\n                day: '\u0627\u0644\u064a\u0648\u0645',\n                settingsName: '\u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0633\u0628\u0648\u0646\u062c \u0628\u0648\u0628',\n                oldAxe: '\u0641\u0623\u0633 \u0642\u062f\u064a\u0645',\n                goodAxe: '\u0641\u0623\u0633 \u062c\u064a\u062f',\n                strongAxe: '\u0641\u0623\u0633 \u0642\u0648\u064a',\n                basicSpear: '\u0631\u0645\u062d \u0623\u0633\u0627\u0633\u064a',\n                sharpSpear: '\u0631\u0645\u062d \u062d\u0627\u062f',\n                poisonSpear: '\u0631\u0645\u062d \u0645\u0633\u0645\u0648\u0645',\n                skateboard: '\u0633\u0643\u064a\u062a \u0628\u0648\u0631\u062f',\n                fastboard: '\u0644\u0648\u062d \u0633\u0631\u064a\u0639',\n                superboard: '\u0644\u0648\u062d \u062e\u0627\u0631\u0642',\n                owned: '\u0645\u0645\u0644\u0648\u0643',\n                introText: \"\u0633\u0628\u0648\u0646\u062c \u0628\u0648\u0628!<br>\u0644\u064a\u0627\u0644\u064a \u0628\u064a\u0643\u064a\u0646\u064a \u0628\u0648\u062a\u0648\u0645\",\n                // Game messages\n                nightApproaching: '\u0627\u0644\u0644\u064a\u0644 \u064a\u0642\u062a\u0631\u0628',\n                nightApproachingHungry: '\u0627\u0644\u0644\u064a\u0644 \u064a\u0642\u062a\u0631\u0628\u060c \u0627\u0644\u063a\u0632\u0627\u0644\u0629 \u062c\u0627\u0626\u0639\u0629',\n                nightApproachingDemonic: '\u0627\u0644\u0644\u064a\u0644 \u064a\u0642\u062a\u0631\u0628\u060c \u0627\u0644\u063a\u0632\u0627\u0644\u0629 \u0634\u064a\u0637\u0627\u0646\u064a\u0629 \u0627\u0644\u0644\u064a\u0644\u0629',\n                campfireAlmostOut: '\u0627\u0644\u0646\u0627\u0631 \u0639\u0644\u0649 \u0648\u0634\u0643 \u0627\u0644\u0627\u0646\u0637\u0641\u0627\u0621',\n                cookMeat: '\u0645\u0645\u0645... \u0644\u062d\u0645 \u0645\u0634\u0648\u064a!',\n                notEnoughWood: '\u0644\u0627 \u064a\u0643\u0641\u064a \u0627\u0644\u062e\u0634\u0628!',\n                campfireProtects: '\u0627\u0644\u0646\u0627\u0631 \u062a\u062d\u0645\u064a\u0643 \u0645\u0646 \u0627\u0644\u0648\u062d\u0648\u0634',\n                campfireLevel: (n) => `\u0627\u0644\u0646\u0627\u0631 \u0648\u0635\u0644\u062a \u0644\u0644\u0645\u0633\u062a\u0648\u0649 ${n}!`,\n                newUpgrades: '\u062a\u0631\u0642\u064a\u0627\u062a \u062c\u062f\u064a\u062f\u0629 \u0645\u062a\u0627\u062d\u0629 \u0641\u064a \u0637\u0627\u0648\u0644\u0629 \u0627\u0644\u0635\u0646\u0639!',\n                radarActivated: '\u062a\u0645 \u062a\u0641\u0639\u064a\u0644 \u0645\u062d\u0637\u0629 \u0627\u0644\u0631\u0627\u062f\u0627\u0631!',\n                survived99: '\u0623\u0646\u0627 \u062c\u0627\u0647\u0632! \u0646\u062c\u0648\u062a 99 \u0644\u064a\u0644\u0629 \u0641\u064a \u0628\u064a\u0643\u064a\u0646\u064a \u0628\u0648\u062a\u0648\u0645!',\n                maxCampfireLevel: '\u0623\u0642\u0635\u0649 \u0645\u0633\u062a\u0648\u0649 \u0644\u0644\u0646\u0627\u0631',\n                levelProgress: (l, x, m) => `\u0627\u0644\u0645\u0633\u062a\u0648\u0649 ${l}: ${x}/${m}`,\n                childrenRescued: (n, m) => `\u062a\u0645 \u0625\u0646\u0642\u0627\u0630 ${n} \u0645\u0646 ${m} \u0623\u0637\u0641\u0627\u0644`,\n                gameOver: '\u064a\u0627 \u0635\u0644\u0635\u0629 \u0627\u0644\u062a\u0627\u0631\u062a\u0627\u0631! \u062d\u0627\u0648\u0644 \u0645\u062c\u062f\u062f\u0627\u064b!',\n                tryAgain: '\u062d\u0627\u0648\u0644 \u0645\u062c\u062f\u062f\u0627\u064b',\n                allRescued: (d) => `\u062a\u0645 \u0625\u0646\u0642\u0627\u0630 \u062c\u0645\u064a\u0639 \u0627\u0644\u0623\u0637\u0641\u0627\u0644<br>\u0641\u064a ${d} \u064a\u0648\u0645!`,\n                keepPlaying: '\u0627\u0633\u062a\u0645\u0631 \u0641\u064a \u0627\u0644\u0644\u0639\u0628',\n                ateMultipleMeat: (n) => `\u0623\u0643\u0644 ${n} \u0642\u0637\u0639\u0629 \u0644\u062d\u0645 \u0645\u0634\u0648\u064a!`,\n                requiresCampfire: (n) => `\u064a\u062a\u0637\u0644\u0628\\n\u0645\u0633\u062a\u0648\u0649 ${n}\\n\u0646\u0627\u0631`\n            }\n        };\n\n        function applyLanguage(lang) {\n            currentLang = lang;\n            const t = TRANSLATIONS[lang];\n            const isAr = lang === 'ar';\n\n            // Toggle button label\n            const langBtn = document.getElementById('langToggleBtn');\n            if (langBtn) langBtn.textContent = t.langBtn;\n\n            // Direction on crafting / wardrobe dialogs\n            const dir = isAr ? 'rtl' : 'ltr';\n            ['craftingDialog', 'wardrobeDialog'].forEach(id => {\n                const el = document.getElementById(id);\n                if (el) el.style.direction = dir;\n            });\n\n            // Main buttons\n            const craftBtn = document.getElementById('craftButton');\n            if (craftBtn) craftBtn.textContent = t.craft;\n\n            const wardrobeBtn = document.getElementById('wardrobeButton');\n            if (wardrobeBtn) wardrobeBtn.textContent = t.wardrobe;\n\n            const craftingCloseBtn = document.getElementById('craftingCloseButton');\n            if (craftingCloseBtn) craftingCloseBtn.textContent = t.done;\n\n            const wardrobeCloseBtn = document.getElementById('wardrobeCloseButton');\n            if (wardrobeCloseBtn) wardrobeCloseBtn.textContent = t.done;\n\n            // Dialog headers\n            const craftingHeader = document.getElementById('craftingHeader');\n            if (craftingHeader) craftingHeader.textContent = t.craftUpgrade;\n\n            const wardrobeHeader = document.getElementById('wardrobeHeader');\n            if (wardrobeHeader) wardrobeHeader.textContent = t.chooseSkin;\n\n            // Bar labels\n            const healthLabel = document.getElementById('healthBarLabel');\n            if (healthLabel) healthLabel.textContent = t.health;\n\n            const hungerLabel = document.getElementById('hungerBarLabel');\n            if (hungerLabel) hungerLabel.textContent = t.hunger;\n\n            const fireLabel = document.getElementById('fireBarLabel');\n            if (fireLabel) fireLabel.textContent = t.fire;\n\n            // Day counter\n            const dayCounter = document.getElementById('dayCounter');\n            if (dayCounter) {\n                const dayNum = window.gameConfig ? window.gameConfig.ui.day : 1;\n                dayCounter.textContent = isAr ? `${t.day} ${dayNum}` : `Day ${dayNum}`;\n            }\n\n            // Crafting item names\n            const nameMap = {\n                'craftOldAxe': t.oldAxe,\n                'craftGoodAxe': t.goodAxe,\n                'craftStrongAxe': t.strongAxe,\n                'craftBasicSpear': t.basicSpear,\n                'craftSharpSpear': t.sharpSpear,\n                'craftPoisonSpear': t.poisonSpear,\n                'craftBasicSkateboard': t.skateboard,\n                'craftFastSkateboard': t.fastboard,\n                'craftSuperSkateboard': t.superboard\n            };\n\n            Object.entries(nameMap).forEach(([id, name]) => {\n                const el = document.getElementById(id);\n                if (el) {\n                    const nameEl = el.querySelector('.craftingItemName');\n                    if (nameEl) nameEl.textContent = name;\n                }\n            });\n\n            // Owned labels in crafting\n            document.querySelectorAll('.craftingItemOwned').forEach(el => {\n                el.textContent = t.owned;\n            });\n\n            // Intro text\n            const introTextEl = document.getElementById('introText');\n            if (introTextEl) introTextEl.innerHTML = t.introText;\n\n            // Leaderboard button\n            const lbBtn = document.getElementById('leaderboardBtn');\n            if (lbBtn) lbBtn.textContent = isAr ? '\ud83c\udfc6 \u0635\u062f\u0627\u0631\u0629' : '\ud83c\udfc6 Board';\n\n            // Leaderboard modal title & close button\n            const lbTitle = document.getElementById('leaderboardTitle');\n            if (lbTitle) lbTitle.textContent = isAr ? '\ud83c\udfc6 \u0644\u0648\u062d\u0629 \u0627\u0644\u0635\u062f\u0627\u0631\u0629' : '\ud83c\udfc6 Leaderboard';\n            const lbClose = document.getElementById('leaderboardCloseBtn');\n            if (lbClose) lbClose.textContent = isAr ? '\u0625\u063a\u0644\u0627\u0642' : 'Close';\n\n            // Dynamic inventory labels & bars (only when game is initialized)\n            if (typeof updateXPBar === 'function') updateXPBar();\n            if (typeof updateWeaponInventory === 'function') updateWeaponInventory();\n            if (typeof updateSkateboardInventory === 'function') updateSkateboardInventory();\n            if (typeof updateFirewoodInventory === 'function') updateFirewoodInventory();\n            if (typeof updateMeatInventory === 'function') updateMeatInventory();\n            if (typeof updateCraftingButtonStates === 'function') updateCraftingButtonStates();\n        }\n\n        function toggleLanguage() {\n            applyLanguage(currentLang === 'en' ? 'ar' : 'en');\n        }\n\n        function run(mode) {\n            gameMode = mode;\n            // Apply default language immediately\n            applyLanguage(currentLang);\n            \n            // Show game parameters UI\n            lib.showGameParameters({\n                name: 'SpongeBob Settings',\n                params: {\n                    'Tree Density': {\n                        key: 'gameConfig.world.treeDensity',\n                        type: 'slider',\n                        min: 0.1,\n                        max: 2.0,\n                        step: 0.1,\n                        onChange: (value) => {\n                            window.gameConfig.world.treeDensity = value;\n                            // Clear tree cache to regenerate with new density\n                            trees.clear();\n                        }\n                    },\n                    'Day': {\n                        key: 'gameConfig.ui.day',\n                        type: 'number',\n                        min: 1,\n                        max: 99,\n                        onChange: (value) => {\n                            window.gameConfig.ui.day = value;\n                            { const t = TRANSLATIONS[currentLang]; document.getElementById('dayCounter').textContent = currentLang === 'ar' ? `${t.day} ${value}` : `Day ${value}`; }\n                        }\n                    },\n                    'Day Length (seconds)': {\n                        key: 'gameConfig.dayLength',\n                        type: 'number',\n                        min: 10,\n                        max: 1800,\n                        onChange: (value) => {\n                            window.gameConfig.dayLength = value;\n                        }\n                    },\n                    'Fire Duration (seconds)': {\n                        key: 'gameConfig.fireDuration',\n                        type: 'number',\n                        min: 5,\n                        max: 300,\n                        onChange: (value) => {\n                            window.gameConfig.fireDuration = value;\n                        }\n                    },\n                    'Message Text Size': {\n                        key: 'gameConfig.ui.messageTextSize',\n                        type: 'slider',\n                        min: 20,\n                        max: 60,\n                        step: 1,\n                        onChange: (value) => {\n                            window.gameConfig.ui.messageTextSize = value;\n                            // Update existing message elements\n                            const messageElements = document.querySelectorAll('.message');\n                            messageElements.forEach(el => {\n                                el.style.fontSize = value + 'px';\n                            });\n                        }\n                    },\n                    'Message Gap': {\n                        key: 'gameConfig.ui.messageGap',\n                        type: 'slider',\n                        min: 20,\n                        max: 100,\n                        step: 2,\n                        onChange: (value) => {\n                            window.gameConfig.ui.messageGap = value;\n                        }\n                    },\n                    'Show Player Position': {\n                        key: 'gameConfig.ui.showPlayerPosition',\n                        type: 'checkbox',\n                        onChange: (value) => {\n                            window.gameConfig.ui.showPlayerPosition = value;\n                            updatePlayerCoordinatesVisibility();\n                        }\n                    },\n                    'Skateboard Speed Bonus': {\n                        key: 'gameConfig.ui.skateboardSpeedBonus',\n                        type: 'slider',\n                        min: 1.0,\n                        max: 3.0,\n                        step: 0.1,\n                        onChange: (value) => {\n                            window.gameConfig.ui.skateboardSpeedBonus = value;\n                        }\n                    }\n                }\n            });\n            \n            // Start intro sequence\n            // Start the intro screen timer immediately (not after assets load)\n            const introStartTime = Date.now();\n            const minIntroTime = 2000; // Minimum time to show intro (2 seconds)\n\n            // Show loading text\n            const loadingText = document.getElementById('loadingText');\n            if (loadingText) {\n                loadingText.style.display = 'block';\n            }\n    \n            preloadAssets(() => {\n                initializeGame();\n\n                // Hide loading text instantly once critical assets are loaded\n                if (loadingText) {\n                    loadingText.style.display = 'none';\n                }\n\n                // Start loading late assets (bear and children) in the background\n                lateLoadAssets(() => {\n                    initializeChildren();\n                });\n\n                // Calculate how long we've already shown the intro\n                const elapsedTime = Date.now() - introStartTime;\n                const remainingTime = Math.max(0, minIntroTime - elapsedTime);\n\n                // Hide intro screen, ensuring minimum display time\n                setTimeout(() => {\n                    hideIntroScreen();\n                }, remainingTime);\n            });\n        }\n    </script>\n</body>\n</html>", "game_config": "{\n  \"player\": {\n    \"startX\": 0,\n    \"startY\": -220,\n    \"level\": \"1\",\n    \"xp\": \"0\"\n  },\n  \"world\": {\n    \"treeDensity\": \"1.5\",\n    \"seed\": 12345\n  },\n  \"ui\": {\n    \"day\": 1,\n    \"theme\": \"forest_journal\",\n    \"showInstructions\": true,\n    \"settingsPanelOpen\": false,\n    \"messageTextSize\": 34.2,\n    \"messageGap\": \"52\",\n    \"showPlayerPosition\": false,\n    \"skateboardSpeedBonus\": 1.6\n  },\n  \"dayLength\": 20,\n  \"fireDuration\": 60,\n  \"inventory\": {\n    \"firewood\": 0,\n    \"meat\": 0,\n    \"hasPoisonSpear\": false,\n    \"hasSkateBoard\": true,\n    \"skateboardEquipped\": false,\n    \"currentSkinId\": \"spongebob_skin\"\n  },\n  \"frogsKilled\": 0,\n  \"poisonSpearSpawned\": false,\n  \"firstFrogSpawned\": false\n}", "game_design_document": "", "persistent_storage_config": {"leaderboard": {"sort_ascending": true}}, "game_metadata": {"game_id": "01KVEB0MS9ZH1PTMYCCHKQG74Q", "title": "\u0648\u0642\u062a \u0627\u0644\u0645\u063a\u0627\u0645\u0631\u0629 \u0627\u0644\u0628\u0642\u0627\u0621 99 \u064a\u0648\u0645 \u0641\u064a \u0627\u0644\u063a\u0627\u0628\u0629 \u0645\u0639 \u0641\u0646 ", "description": "\u0627\u0644\u0628\u0642\u0627\u0621 99 \u0644\u064a\u0644\u0629 \u0641\u064a \u0627\u0644\u063a\u0627\u0628\u0629 \u0645\u0639 \u0627\u0644\u0648\u062d\u0648\u0634  \u0628\u0634\u062e\u0635\u064a\u0629 \u0641\u0646 \u0645\u0646 \u0648\u0642\u062a \u0627\u0644\u0645\u063a\u0627\u0645\u0631\u0629  \u0648\u0645\u062d\u0627\u0648\u0644\u0629 \u0627\u0646\u0642\u0627\u0630 \u0627\u0644\u0646\u0627\u0633 \u0627\u0644\u0645\u062d\u062a\u062c\u0632\u064a\u0646 \u0641\u064a \u0627\u0644\u063a\u0627\u0628\u0629", "thumbnail_url": "https://d2oir5eh8rty2e.cloudfront.net/assets/images/thumbnail_cacd3873-855e-42b6-b2ac-bc41b2a82b26.webp", "created_at": 1781819006.0, "updated_at": 1781819093777.8936, "art_style": null, "is_remix": true, "base_game_id": "01KVC1NHNCV7MMX4NNQE1HV767"}, "task_plan": null}