feat(gamedev): ronda 1 — pixelize + luma→alpha + export-godot (grupo gamedev)
Tres funciones CPU-only del lote gamedev 2D + 2 helpers puros + grupo de capacidad: - comfyui_pixelize_image_py_ml (impure): Fase 2 pixelart — downscale nearest + cuantizacion a N colores / paleta fija (game-boy/pico-8/nes) + re-upscale nearest. - comfyui_matting_luma_to_alpha_py_ml (impure): frame VFX sobre negro -> RGBA por luminancia ponderada (translucidos con additive blend). - comfyui_export_asset_to_godot_py_pipelines (impure): puente ComfyUI -> Godot 4 — copia a res://assets/<dir> por kind + .import por tipo + filtro Nearest si pixelart + reimport headless best-effort. Compone los 2 helpers puros. - godot_map_asset_dir_py_core, godot_clean_asset_name_py_core (pure): nucleos reutilizables del pipeline. - docs/capabilities/gamedev-2d.md + INDEX: grupo nuevo gamedev. Tests 33/33 verdes (offline PIL/numpy). Golden real verificado: asset de ~/ComfyUI/output -> /tmp/godot_test_proj con .import correcto y reimport headless real de Godot 4.7. Sin GPU, sin red, sin tocar proyectos del usuario. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
---
|
||||
name: comfyui_pixelize_image
|
||||
kind: function
|
||||
lang: py
|
||||
domain: ml
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def comfyui_pixelize_image(src_path: str, dst_path: str, *, downscale: int = 8, colors: int = 16, palette=None, dither: bool = False, upscale_back: bool = True) -> dict"
|
||||
description: "Post-proceso pixel-perfect (Fase 2 pixelart): imagen -> downscale nearest-neighbor por factor (colapsa cada bloque borroso a un pixel duro) -> cuantizacion a N colores (MEDIANCUT) o a una paleta fija embebida (game-boy / pico-8 / nes / lista de hex) -> opcional re-upscale nearest conservando los pixeles duros. Convierte el 'pixelart borroso de IA' en pixelart de verdad. Nucleo PIL puro, CPU-only: sin GPU, sin red. Devuelve {ok, out_path, size, n_colors_final, error}. Impura solo por la lectura/escritura de disco."
|
||||
tags: [comfyui, gamedev, pixelart, ml, pil, quantize, palette, image]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_py_core"
|
||||
imports: []
|
||||
params:
|
||||
- name: src_path
|
||||
desc: "ruta de la imagen de entrada (PNG/JPG/...)."
|
||||
- name: dst_path
|
||||
desc: "ruta del PNG de salida (se crea el directorio si falta)."
|
||||
- name: downscale
|
||||
desc: "factor entero de reduccion nearest (>=1); cada bloque downscale x downscale px colapsa a 1 pixel. 1 = solo cuantiza sin colapsar el grid. keyword-only."
|
||||
- name: colors
|
||||
desc: "numero de colores objetivo (2..256) cuando palette es None; cuantizacion MEDIANCUT determinista. keyword-only."
|
||||
- name: palette
|
||||
desc: "None (auto a 'colors'), nombre de paleta fija builtin ('game-boy','pico-8','nes') o lista de hex ('#rrggbb'/'rrggbb'). Una paleta fija ignora 'colors'. keyword-only."
|
||||
- name: dither
|
||||
desc: "aplica Floyd-Steinberg al cuantizar (off por defecto = pixelart limpio). keyword-only."
|
||||
- name: upscale_back
|
||||
desc: "re-escala nearest al tamano original (preview con pixeles duros). False deja la imagen pequena. keyword-only."
|
||||
output: "dict con ok (bool), out_path (str), size ([w,h] de la imagen final), n_colors_final (int, colores distintos del resultado), error (str, vacio si OK)."
|
||||
tested: true
|
||||
tests: [test_golden_downscale_quantize, test_no_upscale_back_keeps_small, test_edge_fixed_palette_game_boy, test_edge_palette_list_hex, test_edge_downscale_1_only_quantizes, test_error_missing_src, test_error_downscale_zero, test_error_bad_palette]
|
||||
test_file_path: "python/functions/ml/comfyui_pixelize_image_test.py"
|
||||
file_path: "python/functions/ml/comfyui_pixelize_image.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
|
||||
from ml.comfyui_pixelize_image import comfyui_pixelize_image
|
||||
|
||||
# Crudo SDXL+pixel-art-xl 1024x1024 -> pixelart 16 colores, grid de 128
|
||||
res = comfyui_pixelize_image(
|
||||
os.path.expanduser("~/ComfyUI/output/pixelart_00001_.png"),
|
||||
"/tmp/hero_pixel.png",
|
||||
downscale=8, colors=16,
|
||||
)
|
||||
# {'ok': True, 'out_path': '/tmp/hero_pixel.png', 'size': [1024, 1024], 'n_colors_final': 16, 'error': ''}
|
||||
|
||||
# Forzar la paleta retro Game Boy (4 colores) y dejar la imagen pequena (sin upscale)
|
||||
comfyui_pixelize_image("/tmp/hero_pixel.png", "/tmp/hero_gb.png",
|
||||
palette="game-boy", upscale_back=False)
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Fase 2 del pipeline pixelart: tras generar el crudo (SDXL + LoRA `pixel-art-xl`),
|
||||
para colapsar el grid borroso a pixeles duros y limitar la paleta. Tambien sirve
|
||||
para "pixelizar" cualquier imagen (sprite, render, foto) a estetica retro sin
|
||||
tocar la GPU. Para llevar el resultado a Godot con filtro Nearest:
|
||||
`comfyui_export_asset_to_godot(out, "pixelart", proj)`.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **nearest, no lanczos**: el downscale usa NEAREST a proposito; interpolar suave
|
||||
re-difumina el grid. No lo cambies por "calidad".
|
||||
- `palette` fija (game-boy/pico-8/nes o lista de hex) **ignora** `colors`. La
|
||||
paleta se rellena internamente repitiendo su ultimo color para que `quantize`
|
||||
no introduzca un negro extra por entradas vacias (bug arreglado en v1.0.0).
|
||||
- `downscale` con `upscale_back=False` deja la imagen de `w//downscale x h//downscale`:
|
||||
util para spritesheets compactos; con `True` vuelve al tamano original con bordes
|
||||
duros (preview).
|
||||
- Todo error es **dict `ok=False`** (no excepcion): `src_path` inexistente,
|
||||
`downscale<1`, paleta desconocida -> `error` explica. No crashea ni borra nada.
|
||||
- `n_colors_final` cuenta colores distintos reales del PNG escrito; con paleta fija
|
||||
puede ser **menor** que el tamano de la paleta si la imagen no usa todos.
|
||||
- CPU-only: no toca la GPU ni el servidor ComfyUI; corre en cualquier interprete
|
||||
con Pillow.
|
||||
Reference in New Issue
Block a user