🎨 Add 42 new demo assets - Kai animations, zombies, buildings, terrain, environment
Generated assets (dual-style): - Kai run animations (East/West, 16 frames) - Kai portrait (neutral, 2 styles) - Zombie walk/attack cycles (6 frames) - Buildings: shack, campfire, well, chest (8 assets) - Terrain: stone path, grass variation (4 tiles) - Environment: oak tree, rock, bush, storage (10 objects) Total: 42 new PNG files (21 base × 2 styles) + Batch generation scripts and manifests + Demo readiness checklist
This commit is contained in:
217
scripts/batch_asset_generation.py
Normal file
217
scripts/batch_asset_generation.py
Normal file
@@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Batch Asset Generation for NovaFarma Demo
|
||||
Generates all missing assets with dual-style system
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Asset definitions with proper organization
|
||||
ASSET_QUEUE = {
|
||||
"kai_animations": {
|
||||
"category": "demo/characters",
|
||||
"assets": [
|
||||
# Run East (4 frames)
|
||||
{"name": "kai_run_east_1", "prompt": "Kai running EAST, frame 1/4, left leg forward, right arm back"},
|
||||
{"name": "kai_run_east_2", "prompt": "Kai running EAST, frame 2/4, mid-stride, both feet off ground"},
|
||||
{"name": "kai_run_east_3", "prompt": "Kai running EAST, frame 3/4, right leg forward, left arm back"},
|
||||
{"name": "kai_run_east_4", "prompt": "Kai running EAST, frame 4/4, landing pose"},
|
||||
|
||||
# Run West (4 frames)
|
||||
{"name": "kai_run_west_1", "prompt": "Kai running WEST, frame 1/4, left leg forward"},
|
||||
{"name": "kai_run_west_2", "prompt": "Kai running WEST, frame 2/4, mid-stride"},
|
||||
{"name": "kai_run_west_3", "prompt": "Kai running WEST, frame 3/4, right leg forward"},
|
||||
{"name": "kai_run_west_4", "prompt": "Kai running WEST, frame 4/4, landing"},
|
||||
|
||||
# Weapon actions
|
||||
{"name": "kai_sword_swing_east", "prompt": "Kai swinging sword to the east, mid-swing action"},
|
||||
{"name": "kai_sword_swing_west", "prompt": "Kai swinging sword to the west, mid-swing action"},
|
||||
{"name": "kai_axe_chop", "prompt": "Kai chopping with axe overhead"},
|
||||
|
||||
# Portraits
|
||||
{"name": "kai_portrait_neutral", "prompt": "Kai portrait, neutral serious expression, close-up face"},
|
||||
{"name": "kai_portrait_happy", "prompt": "Kai portrait, slight smile, determined happy"},
|
||||
{"name": "kai_portrait_sad", "prompt": "Kai portrait, sad expression, concerned"},
|
||||
]
|
||||
},
|
||||
|
||||
"zombies": {
|
||||
"category": "demo/characters",
|
||||
"assets": [
|
||||
# Zombie walk
|
||||
{"name": "zombie_walk_1", "prompt": "Zombie worker shambling, walk frame 1/4, left leg forward"},
|
||||
{"name": "zombie_walk_2", "prompt": "Zombie worker shambling, walk frame 2/4, dragging feet"},
|
||||
{"name": "zombie_walk_3", "prompt": "Zombie worker shambling, walk frame 3/4, right leg forward"},
|
||||
{"name": "zombie_walk_4", "prompt": "Zombie worker shambling, walk frame 4/4, stumbling"},
|
||||
|
||||
# Zombie attack
|
||||
{"name": "zombie_attack_1", "prompt": "Zombie worker attacking, frame 1/4, arms reaching forward"},
|
||||
{"name": "zombie_attack_2", "prompt": "Zombie worker attacking, frame 2/4, lunging motion"},
|
||||
{"name": "zombie_attack_3", "prompt": "Zombie worker attacking, frame 3/4, biting motion"},
|
||||
{"name": "zombie_attack_4", "prompt": "Zombie worker attacking, frame 4/4, return stance"},
|
||||
|
||||
# Variants
|
||||
{"name": "zombie_runner", "prompt": "Fast zombie runner, athletic pose, sprinting stance"},
|
||||
{"name": "zombie_bloated", "prompt": "Bloated zombie, swollen belly, slow heavy build"},
|
||||
{"name": "zombie_corpse", "prompt": "Zombie corpse on ground, defeated, lying down"},
|
||||
]
|
||||
},
|
||||
|
||||
"terrain": {
|
||||
"category": "demo/terrain",
|
||||
"assets": [
|
||||
# Grass variations
|
||||
{"name": "grass_tile_2", "prompt": "Grass tile variation 2, slightly different grass pattern"},
|
||||
{"name": "grass_tile_3", "prompt": "Grass tile variation 3, with small flowers"},
|
||||
{"name": "grass_tile_4", "prompt": "Grass tile variation 4, with rocks"},
|
||||
|
||||
# Stone path
|
||||
{"name": "stone_path_straight", "prompt": "Stone path tile, straight section, cobblestones"},
|
||||
{"name": "stone_path_corner", "prompt": "Stone path corner tile, 90 degree turn"},
|
||||
{"name": "stone_path_cross", "prompt": "Stone path crossroads, 4-way intersection"},
|
||||
{"name": "stone_path_end", "prompt": "Stone path end cap, rounded edge"},
|
||||
|
||||
# Corners
|
||||
{"name": "grass_corner_ne", "prompt": "Grass to dirt corner, northeast transition"},
|
||||
{"name": "grass_corner_nw", "prompt": "Grass to dirt corner, northwest transition"},
|
||||
{"name": "grass_corner_se", "prompt": "Grass to dirt corner, southeast transition"},
|
||||
{"name": "grass_corner_sw", "prompt": "Grass to dirt corner, southwest transition"},
|
||||
]
|
||||
},
|
||||
|
||||
"environment": {
|
||||
"category": "demo/environment",
|
||||
"assets": [
|
||||
# Trees
|
||||
{"name": "oak_tree", "prompt": "Large oak tree, full canopy, healthy green leaves"},
|
||||
{"name": "oak_tree_stump", "prompt": "Cut oak tree stump, chopped down, rings visible"},
|
||||
{"name": "pine_tree", "prompt": "Pine tree, conical shape, dark green needles"},
|
||||
{"name": "dead_tree_2", "prompt": "Dead tree variant 2, bare twisted branches"},
|
||||
|
||||
# Rocks
|
||||
{"name": "rock_small", "prompt": "Small rock, collectible stone, grey granite"},
|
||||
{"name": "rock_medium", "prompt": "Medium rock, obstacle size, moss covered"},
|
||||
{"name": "rock_large_2", "prompt": "Large boulder, imposing size, cracked surface"},
|
||||
|
||||
# Plants
|
||||
{"name": "bush_green_2", "prompt": "Green bush, leafy shrub, decorative foliage"},
|
||||
{"name": "bush_berries", "prompt": "Berry bush, red berries visible, harvestable"},
|
||||
{"name": "flower_yellow", "prompt": "Yellow flowers, small cluster, wildflowers"},
|
||||
{"name": "flower_purple", "prompt": "Purple flowers, delicate petals, garden flowers"},
|
||||
{"name": "grass_tall", "prompt": "Tall grass patch, wild overgrown grass swaying"},
|
||||
{"name": "weeds", "prompt": "Weed patch, unwanted plants, brown dried weeds"},
|
||||
]
|
||||
},
|
||||
|
||||
"buildings": {
|
||||
"category": "demo/buildings",
|
||||
"assets": [
|
||||
{"name": "shack", "prompt": "Wooden shack, upgraded tent, small cabin with door"},
|
||||
{"name": "campfire_lit", "prompt": "Campfire burning, orange flames, cooking fire active"},
|
||||
{"name": "water_well", "prompt": "Stone water well, bucket and rope, medieval well"},
|
||||
{"name": "storage_chest_large", "prompt": "Large storage chest, wooden trunk, iron reinforced"},
|
||||
{"name": "scarecrow", "prompt": "Farm scarecrow, straw figure, tattered clothes, pole"},
|
||||
{"name": "compost_bin", "prompt": "Wooden compost bin, organic waste, farm structure"},
|
||||
]
|
||||
},
|
||||
|
||||
"npcs": {
|
||||
"category": "demo/npcs",
|
||||
"assets": [
|
||||
# Trader
|
||||
{"name": "npc_trader_idle", "prompt": "Merchant trader NPC, standing idle, holding goods bag"},
|
||||
{"name": "npc_trader_portrait", "prompt": "Trader portrait, friendly smile, merchant hat"},
|
||||
|
||||
# Blacksmith
|
||||
{"name": "npc_blacksmith_idle", "prompt": "Blacksmith NPC, muscular build, leather apron, hammer"},
|
||||
{"name": "npc_blacksmith_portrait", "prompt": "Blacksmith portrait, soot on face, serious expression"},
|
||||
|
||||
# Healer
|
||||
{"name": "npc_healer_idle", "prompt": "Healer NPC, robed figure, staff with crystal"},
|
||||
{"name": "npc_healer_portrait", "prompt": "Healer portrait, kind eyes, hood covering hair"},
|
||||
|
||||
# Traveler
|
||||
{"name": "npc_traveler_idle", "prompt": "Mysterious traveler NPC, cloaked, walking staff"},
|
||||
{"name": "npc_traveler_portrait", "prompt": "Traveler portrait, hood obscuring face, mysterious"},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# Style templates
|
||||
STYLE_A_SUFFIX = "Style A: Bold cartoon vector art - thick black outlines, flat vibrant colors, clean cel-shaded style, cheerful indie game aesthetic, white background."
|
||||
|
||||
STYLE_B_SUFFIX = "Style B: Dark gritty noir art - bold black ink outlines, high-contrast desaturated tones, heavy shadows, sketchy crosshatch textures, moody post-apocalyptic atmosphere, black background."
|
||||
|
||||
# Character base descriptions
|
||||
KAI_BASE = """Kai teenage survivor character, dark forest green thick dreadlocks (#2D5016),
|
||||
medium skin tone, large ear gauges, nose piercing and lip piercing,
|
||||
serious determined expression,
|
||||
wearing weathered blue-grey denim jacket with dirt stains,
|
||||
beige t-shirt underneath,
|
||||
torn blue jeans ripped at knees,
|
||||
brown leather combat boots,
|
||||
brown survival backpack with straps and pockets,
|
||||
athletic lean build."""
|
||||
|
||||
ZOMBIE_BASE = """Zombie worker character, decaying grey-green skin, tattered brown work clothes,
|
||||
shambling posture, blank white eyes, exposed bones visible,
|
||||
post-apocalyptic undead laborer."""
|
||||
|
||||
def generate_manifest():
|
||||
"""Generate complete manifest for batch generation"""
|
||||
|
||||
manifest = {
|
||||
"total_assets": 0,
|
||||
"batches": []
|
||||
}
|
||||
|
||||
for batch_name, batch_data in ASSET_QUEUE.items():
|
||||
batch = {
|
||||
"name": batch_name,
|
||||
"category": batch_data["category"],
|
||||
"assets": []
|
||||
}
|
||||
|
||||
for asset in batch_data["assets"]:
|
||||
# Determine character base
|
||||
char_base = ""
|
||||
if "kai" in asset["name"]:
|
||||
char_base = KAI_BASE
|
||||
elif "zombie" in asset["name"]:
|
||||
char_base = ZOMBIE_BASE
|
||||
|
||||
# Create full prompts for both styles
|
||||
base_prompt = f"{char_base}\n{asset['prompt']}" if char_base else asset["prompt"]
|
||||
|
||||
asset_entry = {
|
||||
"name": asset["name"],
|
||||
"styleA_prompt": f"{base_prompt}\n{STYLE_A_SUFFIX}",
|
||||
"styleB_prompt": f"{base_prompt}\n{STYLE_B_SUFFIX}",
|
||||
"target_dir": f"assets/images/{batch_data['category']}"
|
||||
}
|
||||
|
||||
batch["assets"].append(asset_entry)
|
||||
manifest["total_assets"] += 2 # Both styles
|
||||
|
||||
manifest["batches"].append(batch)
|
||||
|
||||
return manifest
|
||||
|
||||
def main():
|
||||
manifest = generate_manifest()
|
||||
|
||||
# Save manifest
|
||||
output_file = Path("BATCH_GENERATION_MANIFEST.json")
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(manifest, f, indent=2)
|
||||
|
||||
print(f"✅ Generated manifest: {output_file}")
|
||||
print(f"📊 Total assets to generate: {manifest['total_assets']}")
|
||||
print(f"📦 Total batches: {len(manifest['batches'])}")
|
||||
|
||||
for batch in manifest["batches"]:
|
||||
print(f" • {batch['name']}: {len(batch['assets'])} base assets (×2 styles = {len(batch['assets'])*2})")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user