feat(comfyui): pipeline comfyui_pixelart_real_oneshot — pixelart REAL (PixelOE + cuantizacion dura)
Materializa el metodo ganador del report 0215: generar a alta-res con SDXL + LoRA SDXL_pixel-art, downscale contrast-aware con PixelOE (engine=pixeloe para sprites/personajes) o nearest (tiles), y cuantizacion dura con comfyui_pixelize_image (16 colores libres o paleta fija pico-8/nes/game-boy). - pixeloe_downscale_py_ml: downscale contrast-aware via lib pixeloe con bridge de interprete (la lib vive en el venv de ComfyUI, no en el del registry). No-throw, fallback limpio si pixeloe no disponible. - comfyui_pixelart_real_oneshot_py_pipelines: one-shot que compone build_pixelart + submit + wait + fetch + pixeloe_downscale + pixelize_image. Fallback automatico pixeloe->nearest. Sweet-spot 64px personajes, 32px iconos. Verificado por PIL: personaje 64x64=16 colores, icono 32x32=16 colores (vs ~33k de la imagen de difusion cruda). 100% grid duro + outline nitido. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
---
|
||||
name: comfyui_pixelart_real_oneshot
|
||||
kind: pipeline
|
||||
lang: py
|
||||
domain: pipelines
|
||||
version: "1.0.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, 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. Materializa el metodo ganador del report 0215: generar a alta-res con SDXL + LoRA SDXL_pixel-art, downscale contrast-aware con PixelOE (engine=pixeloe, sprites) o nearest (tiles), y cuantizacion dura con comfyui_pixelize_image (16 colores libres o paleta fija pico-8/nes/game-boy). Sweet-spot 64px personajes, 32px iconos. Fallback automatico pixeloe->nearest. Compone build_pixelart + submit + wait + fetch + pixeloe_downscale + pixelize_image. Impuro: HTTP + disco."
|
||||
tags: [comfyui, gamedev-2d, pixelart, pipelines, sprite, launcher]
|
||||
uses_functions: [comfyui_build_pixelart_workflow_py_ml, comfyui_submit_workflow_py_ml, comfyui_wait_result_py_ml, comfyui_fetch_output_image_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, 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: 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, prompt_id, error}. out_path = PNG final size x size; out_path_upscaled = preview re-escalado; 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
|
||||
# Personaje 64px, 16 colores, motor pixeloe (sprites con silueta).
|
||||
./fn run comfyui_pixelart_real_oneshot "pixel art knight, full body, side view, game sprite"
|
||||
```
|
||||
|
||||
```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) Personaje 64px, paleta libre 16 colores, PixelOE contrast.
|
||||
res = comfyui_pixelart_real_oneshot(
|
||||
"pixel art knight, full body, side view, game sprite",
|
||||
size=64, colors=16, engine="pixeloe", seed=42,
|
||||
dest_dir="~/ComfyUI/output",
|
||||
)
|
||||
print(res["out_path"], res["colors_final"], res["engine_used"]) # ~16 colores, pixeloe
|
||||
|
||||
# (b) Icono 32px de un item.
|
||||
res = comfyui_pixelart_real_oneshot(
|
||||
"pixel art sword icon, single object",
|
||||
size=32, colors=16, engine="pixeloe", seed=7,
|
||||
)
|
||||
|
||||
# (c) Tile sin silueta -> nearest (mas barato) + paleta fija PICO-8.
|
||||
res = comfyui_pixelart_real_oneshot(
|
||||
"pixel art grass texture tile, top down, seamless",
|
||||
size=64, engine="nearest", palette="pico-8", 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 -> downscale -> cuantizar. Usa `engine="pixeloe"` para
|
||||
personajes/criaturas/iconos con silueta (conserva el contorno) y
|
||||
`engine="nearest"` para tiles/texturas/fondos sin contorno (mas barato, CPU puro).
|
||||
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 `<prefix>_<size>px_<engine>_<paleta|qN>.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.
|
||||
`fill_frame=True` (default) empuja al sujeto a llenar el frame; aun asi, para
|
||||
sprites conviene un subject que pida "full body, centered".
|
||||
- No reintenta el sampler: para mejor toma, varia `seed`.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- 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).
|
||||
Reference in New Issue
Block a user