Files
fn_registry/python/functions/ml/assemble_animated_sprite.md
T
egutierrez 6cc90558d4 feat(gamedev-2d): pipeline walk_cycle_oneshot — personaje andando en pixel-art animado
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>
2026-06-28 18:14:46 +02:00

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}.
gamedev-2d
comfyui
sprite
animation
false error_go_core
name desc
frame_paths lista de rutas a PNG RGBA en orden de reproduccion; los que falten o no abran se saltan (aviso en error).
name desc
out_dir directorio de salida; se crea si no existe. Se escriben '<name>_sheet.png' y '<name>.<ext>' dentro.
name desc
name nombre base de los ficheros generados (keyword-only, default 'anim').
name desc
fps frames por segundo de la animacion; duration_ms = round(1000/max(1,fps)) por frame (keyword-only, default 8).
name desc
fmt formato de la animacion: 'webp' (recomendado, lossless, alpha completo) o 'gif' (alpha binario) (keyword-only).
name desc
loop si True la animacion se repite indefinidamente (loop=0); si False una sola vez (keyword-only, default True).
name desc
spritesheet si True genera tambien el sprite sheet horizontal PNG RGBA (keyword-only, default True).
name desc
pad pixeles de separacion transparente entre columnas del sheet (keyword-only, default 0).
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 < 128 se 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 validosok=False.
  • El campo error puede venir no vacio aunque ok=True: ahi van los avisos de frames saltados. ok refleja 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_dir si no existe; si no hay permiso de escritura, el fallo del sheet va a error como aviso y el de la animacion pone ok=False.
  • disposal=2 limpia el lienzo entre frames (transparencia correcta en cada paso); sin el, los frames se acumularian unos sobre otros.