🎨 Day 8: Multi-Style Decision + Game Bible Complete
✅ COMPLETED: - 80-style aesthetic search concluded - Multi-style approach approved (5 styles) - 40 category test assets generated - Style 32 (Cult of Lamb) selected for main characters - Complete Game Design Bible created - Gronk, Ana, Susi characters generated 📄 NEW FILES: - GAME_BIBLE_COMPLETE.md (full design doc) - MULTI_STYLE_TEST_RESULTS_JAN_02_2026.md - PRODUCTION_DIARY_JAN_02_2026.md 🎯 NEXT: Begin bulk asset production with multi-style diversity
This commit is contained in:
186
scripts/analyze_dino_valley_missing.py
Normal file
186
scripts/analyze_dino_valley_missing.py
Normal file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Analyze Dino Valley missing assets
|
||||
Compares manifest vs actual files
|
||||
Generates missing asset list for Vertex AI generation
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Dino Valley full specification from ALL_BIOMES_COMPLETE_BREAKDOWN.md
|
||||
DINO_VALLEY_SPEC = {
|
||||
"fauna": {
|
||||
"count": 16, # 32 PNG (16 types × 2 styles)
|
||||
"items": [
|
||||
"tyrannosaurus_rex", "triceratops", "velociraptor", "stegosaurus",
|
||||
"brachiosaurus", "pterodactyl", "ankylosaurus", "parasaurolophus",
|
||||
"dilophosaurus", "spinosaurus", "iguanodon", "archaeopteryx",
|
||||
"compsognathus", "plesiosaurus", "mosasaurus", "carnotaurus"
|
||||
]
|
||||
},
|
||||
"teren": {
|
||||
"count": 8, # 16 PNG (8 types × 2 styles)
|
||||
"items": [
|
||||
"dino_volcanic_rock", "dino_lava_cracks", "dino_prehistoric_grass",
|
||||
"dino_dirt_brown", "dino_volcanic_ash", "dino_hot_springs",
|
||||
"dino_tar_pit", "dino_fossilized_ground"
|
||||
]
|
||||
},
|
||||
"vegetacija": {
|
||||
"count": 10, # 20 PNG (10 types × 2 styles)
|
||||
"items": [
|
||||
"dino_giant_fern_large", "dino_giant_fern_medium", "dino_fern_small",
|
||||
"dino_cycad", "dino_palm_tree", "dino_giant_mushroom",
|
||||
"dino_prehistoric_vine", "dino_horsetail", "dino_tree_fern",
|
||||
"dino_ginkgo_tree"
|
||||
]
|
||||
},
|
||||
"rekviziti": {
|
||||
"count": 20, # 40 PNG (20 types × 2 styles)
|
||||
"items": [
|
||||
"dino_skull", "dino_bones_pile", "dino_ribcage", "dino_nest",
|
||||
"dino_eggs", "fossil_amber", "fossil_trilobite", "fossil_ammonite",
|
||||
"volcanic_rock_large", "lava_pool", "steam_vent", "tar_bubble",
|
||||
"cave_entrance", "ancient_ruins_pillar", "ancient_ruins_altar",
|
||||
"dino_footprint", "prehistoric_log", "crystal_formation",
|
||||
"geothermal_spring", "obsidian_shard"
|
||||
]
|
||||
},
|
||||
"zgradbe": {
|
||||
"count": 4, # 8 PNG (4 types × 2 styles)
|
||||
"items": [
|
||||
"dino_research_station", "dino_cave_dwelling", "dino_observation_tower",
|
||||
"dino_fossil_excavation_site"
|
||||
]
|
||||
},
|
||||
"hrana": {
|
||||
"count": 16, # 32 PNG (16 types × 2 styles)
|
||||
"items": [
|
||||
"dino_meat_raw", "dino_meat_cooked", "dino_egg_raw", "dino_egg_cooked",
|
||||
"prehistoric_berries", "cycad_fruit", "fern_shoots", "mushroom_caps",
|
||||
"tar_honey", "volcanic_salt", "mineral_water", "bone_broth",
|
||||
"smoked_meat", "dried_berries", "roasted_nuts", "herbal_tea"
|
||||
]
|
||||
},
|
||||
"materiali": {
|
||||
"count": 9, # 18 PNG (9 types × 2 styles)
|
||||
"items": [
|
||||
"dino_bone", "dino_hide", "dino_tooth", "amber_chunk",
|
||||
"obsidian", "volcanic_glass", "fossil_fuel", "tar", "sulfur"
|
||||
]
|
||||
},
|
||||
"oblacila": {
|
||||
"count": 8, # 16 PNG (8 types × 2 styles)
|
||||
"items": [
|
||||
"dino_hide_vest", "dino_hide_pants", "dino_hide_boots",
|
||||
"dino_tooth_necklace", "amber_pendant", "bone_helmet",
|
||||
"hide_gloves", "volcanic_goggles"
|
||||
]
|
||||
},
|
||||
"orodja": {
|
||||
"count": 10, # 20 PNG (10 types × 2 styles)
|
||||
"items": [
|
||||
"bone_pickaxe", "bone_axe", "bone_sword", "bone_spear",
|
||||
"obsidian_knife", "volcanic_hammer", "tar_torch",
|
||||
"fossil_brush", "hide_backpack", "bone_fishing_rod"
|
||||
]
|
||||
},
|
||||
"npcs": {
|
||||
"count": 5, # 10 PNG (5 types × 2 styles)
|
||||
"items": [
|
||||
"paleontologist", "cave_dweller_male", "cave_dweller_female",
|
||||
"dino_keeper", "fossil_trader"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
BASE_PATH = Path("/Users/davidkotnik/repos/novafarma/assets/slike/biomi/dino_valley")
|
||||
|
||||
def scan_existing_assets():
|
||||
"""Scan existing PNG files in Dino Valley"""
|
||||
existing = {
|
||||
"fauna": [],
|
||||
"teren": [],
|
||||
"vegetacija": [],
|
||||
"rekviziti": [],
|
||||
"zgradbe": [],
|
||||
"hrana": [],
|
||||
"materiali": [],
|
||||
"oblacila": [],
|
||||
"orodja": [],
|
||||
"npcs": []
|
||||
}
|
||||
|
||||
for category in existing.keys():
|
||||
category_path = BASE_PATH / category
|
||||
if category_path.exists():
|
||||
for file in category_path.glob("*.png"):
|
||||
# Extract base name without _styleA / _styleB suffix
|
||||
name = file.stem
|
||||
if name.endswith("_stylea") or name.endswith("_styleb"):
|
||||
base_name = name.rsplit("_", 1)[0]
|
||||
else:
|
||||
base_name = name
|
||||
|
||||
if base_name not in existing[category]:
|
||||
existing[category].append(base_name)
|
||||
|
||||
return existing
|
||||
|
||||
def find_missing_assets():
|
||||
"""Compare spec vs existing, return missing list"""
|
||||
existing = scan_existing_assets()
|
||||
missing = {}
|
||||
|
||||
for category, spec in DINO_VALLEY_SPEC.items():
|
||||
missing[category] = {
|
||||
"items": [],
|
||||
"total_png_needed": 0
|
||||
}
|
||||
|
||||
for item in spec["items"]:
|
||||
if item not in existing[category]:
|
||||
missing[category]["items"].append(item)
|
||||
|
||||
# Each item needs 2 PNG (Style A + B)
|
||||
missing[category]["total_png_needed"] = len(missing[category]["items"]) * 2
|
||||
|
||||
return missing
|
||||
|
||||
def generate_report():
|
||||
"""Generate detailed missing assets report"""
|
||||
missing = find_missing_assets()
|
||||
|
||||
total_missing_items = sum(len(cat["items"]) for cat in missing.values())
|
||||
total_missing_png = sum(cat["total_png_needed"] for cat in missing.values())
|
||||
|
||||
print("=" * 60)
|
||||
print("DINO VALLEY MISSING ASSETS REPORT")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
for category, data in missing.items():
|
||||
if data["items"]:
|
||||
print(f"📁 {category.upper()} - {data['total_png_needed']} PNG needed")
|
||||
for item in data["items"]:
|
||||
print(f" ❌ {item}")
|
||||
print()
|
||||
|
||||
print("=" * 60)
|
||||
print(f"TOTAL MISSING ITEMS: {total_missing_items}")
|
||||
print(f"TOTAL MISSING PNG: {total_missing_png} (including both styles)")
|
||||
print("=" * 60)
|
||||
|
||||
# Save to JSON for next script
|
||||
output_file = Path("/Users/davidkotnik/repos/novafarma/scripts/dino_valley_missing.json")
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(missing, f, indent=2)
|
||||
|
||||
print(f"\n✅ Report saved to: {output_file}")
|
||||
|
||||
return missing
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_report()
|
||||
143
scripts/dino_valley_missing.json
Normal file
143
scripts/dino_valley_missing.json
Normal file
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"fauna": {
|
||||
"items": [
|
||||
"tyrannosaurus_rex",
|
||||
"triceratops",
|
||||
"velociraptor",
|
||||
"stegosaurus",
|
||||
"brachiosaurus",
|
||||
"pterodactyl",
|
||||
"ankylosaurus",
|
||||
"parasaurolophus",
|
||||
"dilophosaurus",
|
||||
"spinosaurus",
|
||||
"iguanodon",
|
||||
"archaeopteryx",
|
||||
"compsognathus",
|
||||
"plesiosaurus",
|
||||
"mosasaurus",
|
||||
"carnotaurus"
|
||||
],
|
||||
"total_png_needed": 32
|
||||
},
|
||||
"teren": {
|
||||
"items": [],
|
||||
"total_png_needed": 0
|
||||
},
|
||||
"vegetacija": {
|
||||
"items": [
|
||||
"dino_giant_mushroom",
|
||||
"dino_prehistoric_vine",
|
||||
"dino_horsetail",
|
||||
"dino_tree_fern",
|
||||
"dino_ginkgo_tree"
|
||||
],
|
||||
"total_png_needed": 10
|
||||
},
|
||||
"rekviziti": {
|
||||
"items": [
|
||||
"dino_bones_pile",
|
||||
"dino_ribcage",
|
||||
"dino_nest",
|
||||
"dino_eggs",
|
||||
"fossil_amber",
|
||||
"fossil_trilobite",
|
||||
"fossil_ammonite",
|
||||
"volcanic_rock_large",
|
||||
"lava_pool",
|
||||
"steam_vent",
|
||||
"tar_bubble",
|
||||
"cave_entrance",
|
||||
"ancient_ruins_pillar",
|
||||
"ancient_ruins_altar",
|
||||
"dino_footprint",
|
||||
"prehistoric_log",
|
||||
"crystal_formation",
|
||||
"geothermal_spring",
|
||||
"obsidian_shard"
|
||||
],
|
||||
"total_png_needed": 38
|
||||
},
|
||||
"zgradbe": {
|
||||
"items": [
|
||||
"dino_research_station",
|
||||
"dino_cave_dwelling",
|
||||
"dino_observation_tower",
|
||||
"dino_fossil_excavation_site"
|
||||
],
|
||||
"total_png_needed": 8
|
||||
},
|
||||
"hrana": {
|
||||
"items": [
|
||||
"dino_meat_raw",
|
||||
"dino_meat_cooked",
|
||||
"dino_egg_raw",
|
||||
"dino_egg_cooked",
|
||||
"prehistoric_berries",
|
||||
"cycad_fruit",
|
||||
"fern_shoots",
|
||||
"mushroom_caps",
|
||||
"tar_honey",
|
||||
"volcanic_salt",
|
||||
"mineral_water",
|
||||
"bone_broth",
|
||||
"smoked_meat",
|
||||
"dried_berries",
|
||||
"roasted_nuts",
|
||||
"herbal_tea"
|
||||
],
|
||||
"total_png_needed": 32
|
||||
},
|
||||
"materiali": {
|
||||
"items": [
|
||||
"dino_bone",
|
||||
"dino_hide",
|
||||
"dino_tooth",
|
||||
"amber_chunk",
|
||||
"obsidian",
|
||||
"volcanic_glass",
|
||||
"fossil_fuel",
|
||||
"tar",
|
||||
"sulfur"
|
||||
],
|
||||
"total_png_needed": 18
|
||||
},
|
||||
"oblacila": {
|
||||
"items": [
|
||||
"dino_hide_vest",
|
||||
"dino_hide_pants",
|
||||
"dino_hide_boots",
|
||||
"dino_tooth_necklace",
|
||||
"amber_pendant",
|
||||
"bone_helmet",
|
||||
"hide_gloves",
|
||||
"volcanic_goggles"
|
||||
],
|
||||
"total_png_needed": 16
|
||||
},
|
||||
"orodja": {
|
||||
"items": [
|
||||
"bone_pickaxe",
|
||||
"bone_axe",
|
||||
"bone_sword",
|
||||
"bone_spear",
|
||||
"obsidian_knife",
|
||||
"volcanic_hammer",
|
||||
"tar_torch",
|
||||
"fossil_brush",
|
||||
"hide_backpack",
|
||||
"bone_fishing_rod"
|
||||
],
|
||||
"total_png_needed": 20
|
||||
},
|
||||
"npcs": {
|
||||
"items": [
|
||||
"paleontologist",
|
||||
"cave_dweller_male",
|
||||
"cave_dweller_female",
|
||||
"dino_keeper",
|
||||
"fossil_trader"
|
||||
],
|
||||
"total_png_needed": 10
|
||||
}
|
||||
}
|
||||
175
scripts/vertex_dino_valley_generator.py
Normal file
175
scripts/vertex_dino_valley_generator.py
Normal file
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Vertex AI Imagen Bulk Generator - Dino Valley
|
||||
Generates all missing Dino Valley assets using Google Vertex AI Imagen 3
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
from vertexai.preview.vision_models import ImageGenerationModel
|
||||
|
||||
# Initialize Vertex AI
|
||||
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = os.path.expanduser(
|
||||
"~/.config/gcloud/application_default_credentials.json"
|
||||
)
|
||||
|
||||
PROJECT_ID = "gen-lang-client-0428644398"
|
||||
LOCATION = "us-central1"
|
||||
|
||||
# Style prompts
|
||||
STYLE_A_SUFFIX = """
|
||||
2D game asset, SMOOTH CHIBI-STYLE VECTOR ART (NOT pixel art), clean anti-aliased edges,
|
||||
bold thick black outlines, flat vibrant bright colors, cute playful proportions,
|
||||
simple clean shapes, friendly cartoon aesthetic. Reference style: cute anime/manga chibi characters,
|
||||
smooth polished vector art. Solid bright chroma key green background (#00FF00),
|
||||
no other elements, centered subject, game-ready asset.
|
||||
"""
|
||||
|
||||
STYLE_B_SUFFIX = """
|
||||
2D game asset, dark hand-drawn gritty noir style with dramatic shadows, high contrast,
|
||||
sketchy atmospheric lines, moody lighting, mature post-apocalyptic aesthetic.
|
||||
Solid bright chroma key green background (#00FF00), no other elements, centered subject, game-ready asset.
|
||||
"""
|
||||
|
||||
def load_missing_assets():
|
||||
"""Load missing assets JSON"""
|
||||
json_path = Path("/Users/davidkotnik/repos/novafarma/scripts/dino_valley_missing.json")
|
||||
with open(json_path, 'r') as f:
|
||||
return json.load(f)
|
||||
|
||||
def get_category_description(category):
|
||||
"""Get detailed description for each category"""
|
||||
descriptions = {
|
||||
"fauna": "prehistoric dinosaur creature",
|
||||
"teren": "tileable terrain ground tile",
|
||||
"vegetacija": "prehistoric plant or vegetation",
|
||||
"rekviziti": "prop object or environmental decoration",
|
||||
"zgradbe": "building or structure",
|
||||
"hrana": "food item",
|
||||
"materiali": "crafting material or resource",
|
||||
"oblacila": "clothing or armor piece",
|
||||
"orodja": "tool or weapon",
|
||||
"npcs": "non-player character, full body sprite, clearly visible eyes with pupils and highlights, detailed facial expression"
|
||||
}
|
||||
return descriptions.get(category, "game asset")
|
||||
|
||||
def generate_prompt(item_name, category, style):
|
||||
"""Generate detailed prompt for Vertex AI"""
|
||||
category_desc = get_category_description(category)
|
||||
|
||||
# Clean up item name for prompt
|
||||
display_name = item_name.replace("_", " ").replace("dino ", "")
|
||||
|
||||
# Build base prompt
|
||||
base_prompt = f"{category_desc}: {display_name}, "
|
||||
|
||||
# Add style
|
||||
if style == "A":
|
||||
prompt = base_prompt + STYLE_A_SUFFIX
|
||||
else:
|
||||
prompt = base_prompt + STYLE_B_SUFFIX
|
||||
|
||||
return prompt
|
||||
|
||||
def generate_image_vertex(prompt, output_path):
|
||||
"""Generate single image using Vertex AI Imagen"""
|
||||
try:
|
||||
model = ImageGenerationModel.from_pretrained("imagegeneration@006")
|
||||
|
||||
response = model.generate_images(
|
||||
prompt=prompt,
|
||||
number_of_images=1,
|
||||
aspect_ratio="1:1",
|
||||
safety_filter_level="block_some",
|
||||
person_generation="allow_adult"
|
||||
)
|
||||
|
||||
if response.images:
|
||||
# Save image
|
||||
response.images[0].save(output_path)
|
||||
return True
|
||||
else:
|
||||
print(f" ❌ No images generated for: {output_path.name}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Error generating {output_path.name}: {str(e)}")
|
||||
return False
|
||||
|
||||
def generate_dino_valley():
|
||||
"""Main generation loop"""
|
||||
missing = load_missing_assets()
|
||||
base_path = Path("/Users/davidkotnik/repos/novafarma/assets/slike/biomi/dino_valley")
|
||||
|
||||
total_items = sum(len(cat["items"]) for cat in missing.values())
|
||||
total_png = total_items * 2 # Both styles
|
||||
|
||||
print("=" * 60)
|
||||
print("🦖 DINO VALLEY BULK GENERATION STARTING")
|
||||
print("=" * 60)
|
||||
print(f"Total items: {total_items}")
|
||||
print(f"Total PNG to generate: {total_png}")
|
||||
print(f"Estimated time: {total_png / 6:.1f} minutes")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
generated_count = 0
|
||||
failed_count = 0
|
||||
|
||||
for category, data in missing.items():
|
||||
if not data["items"]:
|
||||
continue
|
||||
|
||||
category_path = base_path / category
|
||||
category_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
print(f"\n📁 CATEGORY: {category.upper()}")
|
||||
print(f"Items to generate: {len(data['items'])}")
|
||||
print("-" * 60)
|
||||
|
||||
for item in data["items"]:
|
||||
# Generate Style A
|
||||
prompt_a = generate_prompt(item, category, "A")
|
||||
output_a = category_path / f"{item}_stylea.png"
|
||||
|
||||
print(f" 🎨 Generating: {item}_stylea.png")
|
||||
if generate_image_vertex(prompt_a, output_a):
|
||||
generated_count += 1
|
||||
print(f" ✅ Success! ({generated_count}/{total_png})")
|
||||
else:
|
||||
failed_count += 1
|
||||
|
||||
time.sleep(1) # Small delay between requests
|
||||
|
||||
# Generate Style B
|
||||
prompt_b = generate_prompt(item, category, "B")
|
||||
output_b = category_path / f"{item}_styleb.png"
|
||||
|
||||
print(f" 🎨 Generating: {item}_styleb.png")
|
||||
if generate_image_vertex(prompt_b, output_b):
|
||||
generated_count += 1
|
||||
print(f" ✅ Success! ({generated_count}/{total_png})")
|
||||
else:
|
||||
failed_count += 1
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# Progress update every 10 items
|
||||
if (generated_count + failed_count) % 20 == 0:
|
||||
progress_pct = (generated_count / total_png) * 100
|
||||
print(f"\n 📊 PROGRESS: {generated_count}/{total_png} ({progress_pct:.1f}%)")
|
||||
print(f" ⏱️ Estimated remaining: {(total_png - generated_count) / 6:.1f} minutes\n")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("🎉 DINO VALLEY GENERATION COMPLETE!")
|
||||
print("=" * 60)
|
||||
print(f"✅ Generated: {generated_count}/{total_png}")
|
||||
print(f"❌ Failed: {failed_count}")
|
||||
print("=" * 60)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import vertexai
|
||||
vertexai.init(project=PROJECT_ID, location=LOCATION)
|
||||
generate_dino_valley()
|
||||
Reference in New Issue
Block a user