--- name: comfyui_pixelart_real_oneshot kind: pipeline lang: py domain: pipelines version: "1.1.0" purity: impure signature: "def comfyui_pixelart_real_oneshot(subject: str, *, size: int = 64, colors: int = 16, engine: str = \"pixeloe\", palette=None, server: str = \"127.0.0.1:8188\", dest_dir: str = \"~/ComfyUI/output\", seed: int = 0, negative: str | None = None, mode: str = \"contrast\", patch_size: int = 16, thickness: int = 2, fill_frame: bool = True, transparent: bool = True, autocrop: bool = True, crop_pad_ratio: float = 0.06, rembg_model: str = \"u2net\", upscale_preview: int = 512, keep_base: bool = True, comfy_python: str | None = None, wait_timeout: float = 300.0, filename_prefix: str = \"pixelart_real\", **gen_kwargs) -> dict" description: "Pipeline one-shot prompt de texto -> sprite pixel-art REAL (grid duro + paleta limitada) en disco, con fondo transparente y sujeto que llena el frame. Materializa el metodo ganador del report 0215, ahora alpha-aware: generar a alta-res con SDXL + LoRA SDXL_pixel-art (rembg recorta el fondo si transparent), AUTOCROP al bbox del contenido + cuadrado (el sujeto llena el frame, no diminuto), downscale contrast-aware con PixelOE (engine=pixeloe, sprites; alpha recombinado aparte porque PixelOE trabaja en RGB) o nearest (tiles), y cuantizacion dura alpha-aware con comfyui_pixelize_image (16 colores libres o paleta fija pico-8/nes/game-boy). Salida PNG RGBA con transparencia real. Sweet-spot 64px personajes, 32px iconos. Fallback automatico pixeloe->nearest. Compone build_pixelart + submit + wait + fetch + crop_to_content + pixeloe_downscale + pixelize_image. Impuro: HTTP + disco." tags: [comfyui, gamedev-2d, pixelart, pipelines, sprite, launcher, alpha, transparent, autocrop] uses_functions: [comfyui_build_pixelart_workflow_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_py_ml, crop_to_content_py_ml, pixeloe_downscale_py_ml, comfyui_pixelize_image_py_ml] uses_types: [] returns: [] returns_optional: false error_type: error_py_core imports: [comfyui_build_pixelart_workflow_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_py_ml, crop_to_content_py_ml, pixeloe_downscale_py_ml, comfyui_pixelize_image_py_ml] params: - name: subject desc: "Prompt positivo (lo que se quiere ver: 'pixel art knight, full body, side view'). No puede estar vacio." - name: size desc: "Lado del grid final en pixeles. 64 personajes/sprites, 32 iconos/objetos simples. keyword-only." - name: colors desc: "Numero de colores de la paleta libre (MEDIANCUT) cuando palette es None. keyword-only." - name: engine desc: "'pixeloe' (downscale contrast-aware, sujetos con silueta) o 'nearest' (downscale simple, tiles/texturas). Fallback automatico a nearest si pixeloe falla. keyword-only." - name: palette desc: "None (paleta libre a `colors`), nombre builtin ('pico-8', 'nes', 'game-boy') o lista de hex. Una paleta fija ignora `colors`. keyword-only." - name: server desc: "host:port del servidor ComfyUI (sin esquema). keyword-only." - name: dest_dir desc: "Directorio donde guardar los PNG (se expande ~). keyword-only." - name: seed desc: "Semilla del KSampler. keyword-only." - name: negative desc: "Prompt negativo; None usa el default de build_pixelart (evita blur/gradientes/anti-alias). keyword-only." - name: mode desc: "Modo de downscale de PixelOE ('contrast' SOTA, 'k-centroid', 'nearest', 'center', 'bicubic'); solo con engine='pixeloe'. keyword-only." - name: patch_size desc: "Tamano de patch de PixelOE (default 16). keyword-only." - name: thickness desc: "Grosor del outline expansion de PixelOE (default 2). keyword-only." - name: fill_frame desc: "Si True anade un hint de encuadre al subject para que el sujeto llene el frame (mejor detalle por pixel tras el downscale). keyword-only." - name: transparent desc: "Si True (default) genera con fondo recortado (rembg en el workflow) y produce sprite RGBA con transparencia real. False para tiles/texturas sin alpha (PNG opaco). keyword-only." - name: autocrop desc: "Si True (default) recorta la imagen base al bbox del contenido + cuadrado antes del downscale, para que el sujeto llene el frame (evita el sprite diminuto). Usa el alpha si transparent, o el color de fondo si no. keyword-only." - name: crop_pad_ratio desc: "Margen relativo que deja el autocrop alrededor del sujeto (0.06 = 6% del lado). keyword-only." - name: rembg_model desc: "Modelo Rembg para recortar el fondo ('u2net' general, 'isnet-anime' anime). Solo aplica si transparent. keyword-only." - name: upscale_preview desc: "Si > 0 escribe ademas un PNG re-escalado nearest a ese lado (preview con pixeles duros, p.ej. 512). 0 lo desactiva. keyword-only." - name: keep_base desc: "Si True conserva el PNG base de alta resolucion; si False lo borra tras pixelizar. keyword-only." - name: comfy_python desc: "Ruta al interprete de ComfyUI (con la lib pixeloe); None autodetecta. keyword-only." - name: wait_timeout desc: "Segundos maximos esperando al server. keyword-only." - name: filename_prefix desc: "Prefijo de los archivos de salida. keyword-only." - name: gen_kwargs desc: "Params extra para comfyui_build_pixelart_workflow (width, height, ckpt_name, lora_strength, use_lcm, steps, cfg, ...). keyword-only (**gen_kwargs)." output: "dict {ok, out_path, out_path_upscaled, base_path, size, colors_final, engine_used, has_alpha, autocrop_applied, prompt_id, error}. out_path = PNG final size x size (RGBA si transparent); out_path_upscaled = preview re-escalado; has_alpha = True si lleva transparencia; autocrop_applied = True si el autocrop recorto la base; engine_used refleja el fallback (pixeloe->nearest). Si falla, ok=False y error explica en que paso. No-throw." tested: false tests: [] test_file_path: "" file_path: "python/functions/pipelines/comfyui_pixelart_real_oneshot.py" --- ## Ejemplo ```bash # Sprite de personaje 64px: RGBA transparente + autocrop (sujeto llena el frame). ./fn run comfyui_pixelart_real_oneshot "pixel art knight, full body, centered" ``` ```python import sys, os sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions")) from pipelines.comfyui_pixelart_real_oneshot import comfyui_pixelart_real_oneshot # (a) Sprite personaje 64px: fondo transparente + autocrop (defaults). res = comfyui_pixelart_real_oneshot( "pixel art knight, full body, centered", size=64, colors=16, engine="pixeloe", seed=42, transparent=True, autocrop=True, dest_dir="~/ComfyUI/output", ) print(res["out_path"], res["colors_final"], res["has_alpha"], res["engine_used"]) # -> 64px RGBA, ~16 colores, has_alpha=True, esquinas transparentes, sujeto ~88% del frame # (b) Icono 32px de un item (sprite con alpha). res = comfyui_pixelart_real_oneshot( "pixel art sword icon, single object", size=32, colors=16, engine="pixeloe", seed=7, ) # (c) Tile sin silueta -> nearest + paleta fija PICO-8, SIN transparencia. res = comfyui_pixelart_real_oneshot( "pixel art grass texture tile, top down, seamless", size=64, engine="nearest", palette="pico-8", transparent=False, autocrop=False, fill_frame=False, ) ``` ## Cuando usarla Cuando quieres pixel-art **de verdad** (grid duro + paleta limitada, verificable por conteo de colores), no la salida cruda de la difusion (que parece pixelada pero tiene decenas de miles de colores y bordes con anti-aliasing). Una sola llamada hace generar -> recortar -> downscale -> cuantizar. Para **sprites de sujeto** (personajes, criaturas, objetos) deja los defaults `transparent=True` + `autocrop=True`: salen RGBA con fondo transparente y el sujeto llena el frame. Usa `engine="pixeloe"` para conservar la silueta. Para **tiles/texturas/fondos** sin contorno usa `engine="nearest"`, `transparent=False`, `autocrop=False` (mas barato, CPU puro, sin alpha). 64px es el sweet-spot de personajes; 32px solo para iconos/objetos simples. ## Gotchas - Impuro: requiere el **servidor ComfyUI vivo** en `server` (default `127.0.0.1:8188`) y los modelos instalados (SDXL Juggernaut + LoRA `SDXL_pixel-art` + `SDXL_lcm-lora`). Si esta caido, falla en submit con `ok=False` y el error de conexion (nunca lanza). - `engine="pixeloe"` necesita la lib `pixeloe`, que vive en el venv de ComfyUI (no en el del registry). `pixeloe_downscale` hace el puente de interprete automaticamente; si no la encuentra, el pipeline **cae a `nearest`** y lo reporta en `engine_used` + `error` (no aborta). - El nodo `PixelOEPixelize+` de ComfyUI_essentials estaba **roto** por un import obsoleto (`pixeloe.pixelize` -> ahora `pixeloe.legacy.pixelize`); por eso el pipeline usa la lib directa via `pixeloe_downscale`, no el nodo del server. - `dest_dir` es un **directorio** (se crea si no existe). Los nombres de salida son `_px__.png` y `..._up.png` (preview). - Una **paleta fija** (`pico-8`/`nes`/`game-boy`/lista hex) ignora `colors` y puede dar menos colores que `colors` si el sujeto no cubre toda la paleta. - Encuadre: si el sujeto ocupa poca area del frame, a 64/32px queda diminuto. Dos mecanismos lo evitan: `fill_frame=True` (hint al prompt) y, sobre todo, `autocrop=True` (default) que recorta al bbox real del contenido + cuadrado tras generar. Con autocrop el sujeto llena ~85-90% del frame aunque el prompt no lo encuadre perfecto. - **transparencia (v1.1.0)**: `transparent=True` (default) mete el nodo `Image Rembg` en el workflow (requiere ese custom node en el server) y produce PNG **RGBA**. Las 4 esquinas salen `alpha==0`. Para tiles/fondos opacos: `transparent=False`. - **alpha a traves de PixelOE**: PixelOE trabaja en RGB y pierde el alpha; el pipeline downscalea el alpha del recorte por separado (nearest al mismo `size`) y lo recombina sobre el grid antes de cuantizar. Por eso el sprite final conserva la transparencia con `engine="pixeloe"`. - Si la generacion sale **toda transparente** (rembg no detecto sujeto), no crashea: el autocrop deja la imagen sin recortar y el resto del pipeline sigue (sprite vacio, `colors_final` bajo). Revisa el `subject` en ese caso. - No reintenta el sampler: para mejor toma, varia `seed`. ## Capability growth log - v1.1.0 (2026-06-28) — sprite-fix: `transparent`/`autocrop`/`crop_pad_ratio`/ `rembg_model`. Arregla los 2 bugs reportados: (1) sprite diminuto -> autocrop al bbox del contenido + cuadrado antes del downscale (sujeto pasa de ~48% a ~88% del frame); (2) sin transparencia -> rembg en el workflow + cuantizacion alpha-aware + alpha recombinado tras PixelOE -> PNG RGBA con esquinas alpha==0. Anade `crop_to_content` a la composicion. Verificado en GPU (knight 64px). - v1.0.0 (2026-06-28) — pipeline inicial. Materializa el metodo ganador del report 0215 (PixelOE contrast downscale -> cuantizacion dura). Compone build_pixelart + submit + wait + fetch + pixeloe_downscale + pixelize_image (issue 0087).