diff --git a/assets/sprites/portraits/ana_portrait.png b/assets/sprites/portraits/ana_portrait.png new file mode 100644 index 000000000..fe9913055 Binary files /dev/null and b/assets/sprites/portraits/ana_portrait.png differ diff --git a/assets/sprites/portraits/arborist_portrait.png b/assets/sprites/portraits/arborist_portrait.png new file mode 100644 index 000000000..00b0f2722 Binary files /dev/null and b/assets/sprites/portraits/arborist_portrait.png differ diff --git a/assets/sprites/portraits/gronk_portrait.png b/assets/sprites/portraits/gronk_portrait.png new file mode 100644 index 000000000..6b3f52ff3 Binary files /dev/null and b/assets/sprites/portraits/gronk_portrait.png differ diff --git a/assets/sprites/portraits/ivan_portrait.png b/assets/sprites/portraits/ivan_portrait.png new file mode 100644 index 000000000..a272fa188 Binary files /dev/null and b/assets/sprites/portraits/ivan_portrait.png differ diff --git a/assets/sprites/portraits/kai_portrait.png b/assets/sprites/portraits/kai_portrait.png new file mode 100644 index 000000000..c02666c37 Binary files /dev/null and b/assets/sprites/portraits/kai_portrait.png differ diff --git a/assets/sprites/portraits/kustos_portrait.png b/assets/sprites/portraits/kustos_portrait.png new file mode 100644 index 000000000..4ff1bd05b Binary files /dev/null and b/assets/sprites/portraits/kustos_portrait.png differ diff --git a/assets/sprites/portraits/pek_portrait.png b/assets/sprites/portraits/pek_portrait.png new file mode 100644 index 000000000..889e9d452 Binary files /dev/null and b/assets/sprites/portraits/pek_portrait.png differ diff --git a/assets/sprites/portraits/tehnik_portrait.png b/assets/sprites/portraits/tehnik_portrait.png new file mode 100644 index 000000000..8712429c6 Binary files /dev/null and b/assets/sprites/portraits/tehnik_portrait.png differ diff --git a/assets/sprites/portraits/zombi_skavt_portrait.png b/assets/sprites/portraits/zombi_skavt_portrait.png new file mode 100644 index 000000000..094430886 Binary files /dev/null and b/assets/sprites/portraits/zombi_skavt_portrait.png differ diff --git a/assets/sprites/portraits/zupan_portrait.png b/assets/sprites/portraits/zupan_portrait.png new file mode 100644 index 000000000..dcc221c0b Binary files /dev/null and b/assets/sprites/portraits/zupan_portrait.png differ diff --git a/scripts/generate_dialogue_portraits.py b/scripts/generate_dialogue_portraits.py new file mode 100644 index 000000000..182c5b634 --- /dev/null +++ b/scripts/generate_dialogue_portraits.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +""" +Generate dialogue portraits (64x64px face crops) from master references +""" +from PIL import Image +import os + +# Character reference mappings +CHARACTERS = { + 'kai_portrait.png': 'references/main_characters/kai/master_reference_nobg.png', + 'ana_portrait.png': 'references/main_characters/ana/master_reference_nobg.png', + 'gronk_portrait.png': 'references/main_characters/gronk/master_reference_nobg.png', + 'ivan_portrait.png': 'references/npcs/ivan_kovac/master_reference_nobg.png', + 'zombi_skavt_portrait.png': 'references/companions/zombie_scout/master_reference_nobg.png', + 'pek_portrait.png': 'references/npcs/pek/master_reference.png', + 'tehnik_portrait.png': 'references/npcs/tehnik/master_reference.png', + 'kustos_portrait.png': 'references/npcs/kustos/master_reference.png', + 'zupan_portrait.png': 'references/npcs/mayor/master_reference.png', + 'arborist_portrait.png': 'references/npcs/arborist/master_reference.png', +} + +def create_portrait(input_path, output_path, size=64): + """Crop top portion (head) from master reference and resize to portrait size""" + if not os.path.exists(input_path): + print(f"⚠️ SKIP: {input_path} not found") + return + + img = Image.open(input_path) + width, height = img.size + + # Crop top 40% (head area) - assuming chibi proportions + crop_height = int(height * 0.4) + head_crop = img.crop((0, 0, width, crop_height)) + + # Resize to 64x64 maintaining aspect ratio + head_crop.thumbnail((size, size), Image.Resampling.LANCZOS) + + # Create new 64x64 image with transparency + portrait = Image.new('RGBA', (size, size), (0, 0, 0, 0)) + + # Center the cropped head + offset = ((size - head_crop.width) // 2, (size - head_crop.height) // 2) + portrait.paste(head_crop, offset, head_crop if head_crop.mode == 'RGBA' else None) + + # Save + portrait.save(output_path, 'PNG') + print(f"✅ Created: {output_path}") + +def main(): + os.makedirs('assets/sprites/portraits', exist_ok=True) + + print("🎭 GENERATING DIALOGUE PORTRAITS FROM MASTER REFERENCES...") + print("=" * 60) + + for portrait_name, reference_path in CHARACTERS.items(): + output_path = f'assets/sprites/portraits/{portrait_name}' + create_portrait(reference_path, output_path) + + print("=" * 60) + print("✅ PORTRAIT GENERATION COMPLETE!") + +if __name__ == '__main__': + main()