55Usage:
66 python3 generate_jimeng_spritesheet.py <agent_key> "<prompt>" [output_path]
77
8- Examples:
9- python3 generate_jimeng_spritesheet.py xiaoai "A cute pixel art chibi AI agent..."
8+ The script generates 3 images (one per animation state), resizes each to 64x64,
9+ and tiles them into a 256x192 spritesheet (4 cols x 3 rows).
10+ Row 0 = idle, Row 1 = work, Row 2 = sleep/error
1011"""
1112import subprocess
1213import urllib .request
1617from PIL import Image
1718
1819OUT_DIR = "/home/ubuntu/claw-visual/packages/web/public/sprites"
19- MCPORTER_BIN = "/home/ubuntu/.local/share/pnpm/mcporter"
2020NODE_PATH = "/home/ubuntu/.local/share/pnpm/global/5/.pnpm/mcporter@0.7.3_hono@4.11.7/node_modules"
2121BUN_BIN = "/home/ubuntu/.bun/bin/bun"
22- NVM_SHELL = "/home/ubuntu/.nvm/nvm.sh"
2322
2423TARGET_W , TARGET_H = 256 , 192
2524FRAME_W , FRAME_H = 64 , 64
@@ -53,7 +52,6 @@ def call_jimeng(prompt: str, aspect_ratio: str = "3:2") -> list[str]:
5352 print (f"STDERR: { result .stderr } " , file = sys .stderr )
5453 raise RuntimeError (f"mcporter call failed with code { result .returncode } " )
5554
56- # Parse URLs from text output
5755 urls = []
5856 for line in result .stdout .split ("\n " ):
5957 line = line .strip ()
@@ -78,26 +76,22 @@ def download_image(url: str) -> Image.Image:
7876def make_spritesheet (images : list [Image .Image ], output_path : str ):
7977 """
8078 Combine up to 3 images into a 256x192 spritesheet (4 cols x 3 rows).
81-
82- Row 0 (idle): image[0] — extract 4 horizontal 64x64 tiles
83- Row 1 (work): image[1] — same
84- Row 2 (sleep): image[2] — same
85-
86- If fewer images available, pad with last image.
79+ Each source image = one animation state (idle/work/sleep), resized to 64x64.
80+ Row 0 (idle): frames[0] tiled 4x
81+ Row 1 (work): frames[1] tiled 4x
82+ Row 2 (sleep): frames[2] tiled 4x
8783 """
8884 result = Image .new ("RGBA" , (TARGET_W , TARGET_H ), (0 , 0 , 0 , 0 ))
8985
90- # Resize each source to 256x192
91- resized = [img .resize ((TARGET_W , TARGET_H ), Image .LANCZOS ) for img in images ]
92- # Pad to 3
93- while len (resized ) < 3 :
94- resized .append (resized [- 1 ])
86+ # Resize each source to 64x64 (single frame)
87+ frames = [img .resize ((FRAME_W , FRAME_H ), Image .LANCZOS ) for img in images ]
88+ while len (frames ) < 3 :
89+ frames .append (frames [- 1 ] if frames else Image .new ("RGBA" , (FRAME_W , FRAME_H ), (0 , 0 , 0 , 0 )))
9590
9691 for row_idx in range (ROWS ):
97- src = resized [row_idx ]
92+ frame = frames [row_idx ]
9893 for col in range (COLS ):
99- tile = src .crop ((col * FRAME_W , 0 , (col + 1 ) * FRAME_W , FRAME_H ))
100- result .paste (tile , (col * FRAME_W , row_idx * FRAME_H ))
94+ result .paste (frame , (col * FRAME_W , row_idx * FRAME_H ))
10195
10296 result .save (output_path )
10397 print (f"Saved: { output_path } ({ result .size } )" )
@@ -107,9 +101,8 @@ def main():
107101 if len (sys .argv ) < 3 :
108102 agent_key = "xiaoai"
109103 prompt = (
110- "A cute pixel art chibi AI agent avatar, 256x192 pixels total, "
111- "64x64 per frame, 4 frames in a row, clean pixel art style, "
112- "bright cheerful expression, simple clean background"
104+ "pixel art chibi AI agent character, solid sky blue background #87CEEB, "
105+ "limited color palette NES style, crisp pixel edges"
113106 )
114107 else :
115108 agent_key = sys .argv [1 ]
@@ -120,17 +113,22 @@ def main():
120113 print (f"=== Generating spritesheet for: { agent_key } ===" )
121114 print (f"Output: { output_path } " )
122115
123- urls = call_jimeng (prompt )
124- if not urls :
125- print ("No URLs returned, exiting." )
126- sys .exit (1 )
116+ # Generate 3 images for 3 states
117+ state_prompts = [
118+ f"{ prompt } - idle pose, standing forward, friendly neutral expression" ,
119+ f"{ prompt } - working pose, hands on keyboard, focused expression" ,
120+ f"{ prompt } - resting or sleeping pose, eyes closed, calm relaxed expression" ,
121+ ]
127122
128123 images = []
129- for i , url in enumerate (urls [:4 ]):
130- try :
131- images .append (download_image (url ))
132- except Exception as e :
133- print (f" Download failed for image { i } : { e } " , file = sys .stderr )
124+ for i , sp in enumerate (state_prompts ):
125+ print (f" State { i + 1 } /3: { sp [:70 ]} ..." )
126+ urls = call_jimeng (sp )
127+ if urls :
128+ try :
129+ images .append (download_image (urls [0 ]))
130+ except Exception as e :
131+ print (f" Download failed: { e } " , file = sys .stderr )
134132
135133 if not images :
136134 print ("No images downloaded." , file = sys .stderr )
0 commit comments