6cc90558d4
Promueve el caso 1 del report 0217 (animacion de sprites de personaje) a un pipeline one-shot: de un prompt de personaje a un sprite sheet + GIF/WEBP en loop, frame-by-frame dirigido por pose (ControlNet OpenPose + seed fija + Rembg) con cada frame pixelizado a NxN RGBA. Nuevas funciones reutilizables (issue 0087, crecimiento por composicion): - comfyui_walk_cycle_oneshot (pipeline): orquesta poses -> generacion -> pixelizado -> ensamblado. No-throw, salta frames que fallan. Modo openpose (esqueletos reales) con fallback prompt-pose. - render_openpose_walk_skeletons: dibuja N esqueletos OpenPose COCO-18 del walk cycle (el insumo que el report 0217 marco como faltante). - comfyui_pixelize_sprite_png: PNG existente -> NxN RGBA pixel-art real (compone crop_to_content + pixeloe_downscale + comfyui_pixelize_image). - assemble_animated_sprite: frames RGBA -> sprite sheet horizontal + WEBP/GIF loop. - comfyui_build_walk_cycle_workflow (pura): grafo API del workflow animado para la UI (ControlNet OpenPose -> KSampler xN seed fija -> ImageBatch -> Rembg -> SaveAnimatedWEBP). Verificado en GPU: GIF/WEBP de caballero andando, 4 frames 32x32 (y 64x64) RGBA con fondo transparente y 16 colores, identidad de silueta consistente, piernas que cambian. Metodo de poses usado: OpenPose real (sin fallback). Evidencia en report 0221. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.2 KiB
5.2 KiB
name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
| name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | params | output | tested | tests | test_file_path | file_path | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| assemble_animated_sprite | function | py | ml | 1.0.0 | impure | def assemble_animated_sprite(frame_paths: list, out_dir: str, *, name: str = "anim", fps: int = 8, fmt: str = "webp", loop: bool = True, spritesheet: bool = True, pad: int = 0) -> dict | Ensambla N frames PNG RGBA (p.ej. los frames de un walk cycle ya pixelizados a 32x32 con alpha) en DOS entregables: un sprite sheet horizontal (1 fila x N columnas) PNG RGBA con la transparencia intacta, y una animacion en loop WEBP lossless o GIF animado. Es la pieza de ensamblado final de cualquier animacion de sprite. Salta frames que falten o no abran (aviso en error, no aborta); normaliza tamano al primer frame valido reescalando con NEAREST. Solo PIL. No-throw. Devuelve {ok, spritesheet_path, animation_path, n_frames, frame_size, fmt, error}. |
|
false | error_go_core |
|
dict con ok (bool, True si se produjo la animacion con >=1 frame valido), spritesheet_path (str, '' si spritesheet=False o fallo), animation_path (str, '' si fallo), n_frames (int, frames validos usados), frame_size ([w,h] del frame normalizado), fmt (str, 'webp'|'gif'), error (str, avisos y/o error; '' si limpio). | false | python/functions/ml/assemble_animated_sprite.py |
Ejemplo
import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.assemble_animated_sprite import assemble_animated_sprite
# Frames de un walk cycle ya pixelizados a 32x32 RGBA (p.ej. salida del pipeline ComfyUI):
frames = [
"/tmp/walk/frame_00.png",
"/tmp/walk/frame_01.png",
"/tmp/walk/frame_02.png",
"/tmp/walk/frame_03.png",
]
res = assemble_animated_sprite(frames, "/tmp/walk_out", name="hero_walk", fps=8, fmt="webp")
# {'ok': True,
# 'spritesheet_path': '/tmp/walk_out/hero_walk_sheet.png',
# 'animation_path': '/tmp/walk_out/hero_walk.webp',
# 'n_frames': 4, 'frame_size': [32, 32], 'fmt': 'webp', 'error': ''}
Cuando usarla
Al final de cualquier pipeline de animacion de sprite, cuando ya tienes los frames
sueltos (pixelizados, con alpha) y necesitas (a) verlos animados en bucle para validar
el ciclo a ojo y (b) un sprite sheet horizontal listo para que un motor de juego lo
trocee por columnas. Tipico despues de generar un walk cycle frame a frame con ComfyUI
y pasarlo por el pixelizado: este es el paso de "juntarlo todo". Usa fmt="webp" por
defecto; fmt="gif" solo si necesitas compatibilidad con visores que no abren WEBP.
Gotchas
- GIF solo tiene alpha binario (1 bit): cada pixel es opaco o totalmente
transparente, los pixeles con
alpha < 128se vuelven transparentes y se pierde el anti-aliasing del borde. WEBP (lossless) es el formato recomendado para sprites con alpha — conserva el canal alpha completo y no ensucia el pixel-art. Usa GIF solo por compatibilidad. - Al guardar GIF, PIL reoptimiza la paleta y el indice de transparencia puede cambiar (p.ej. de 255 a 1 al releer): es normal, los pixeles transparentes se preservan (verificable convirtiendo el frame a RGBA y mirando el canal alpha).
- Frames que faltan o no abren se SALTAN (se anota en
error), no se aborta: la animacion se monta con los frames validos. Si quedan 0 frames validos →ok=False. - El campo
errorpuede venir no vacio aunqueok=True: ahi van los avisos de frames saltados.okrefleja si se genero la animacion, no la ausencia de avisos. - El tamano se normaliza al primer frame valido; los frames de tamano distinto se reescalan con NEAREST (sin interpolacion, preserva el pixel-art duro), lo que puede deformarlos si su aspect ratio difiere. Asegurate de que todos los frames ya vienen al mismo tamano.
- Escribe en disco: crea
out_dirsi no existe; si no hay permiso de escritura, el fallo del sheet va aerrorcomo aviso y el de la animacion poneok=False. disposal=2limpia el lienzo entre frames (transparencia correcta en cada paso); sin el, los frames se acumularian unos sobre otros.