feat(gamedev): comfyui_generate_styled_asset_oneshot — aplica estilo a un asset con auto-post + amplía catálogo a 6 estilos

Pipeline one-shot que aplica un style preset curado a un asset en una llamada
(kind, subject, style_preset) y auto-ejecuta el post-proceso que el estilo declara:
los estilos pixelart (gameboy, pixel-art-retro) salen ya pixelizados del pipeline,
cerrando el hueco #1 del sistema de style presets (report 0190) donde el caller
tenía que llamar comfyui_pixelize_image a mano.

Reutiliza el dispatch _SUPPORTED (kind->builder) de comfyui_generate_asset_pack_oneshot
en vez de redefinir el mapa. Parte pura aislada en styled_asset_build_only para validar
kind/estilo desconocido sin tocar la GPU. Export a Godot consciente del post (pixelart
si hubo pixelize, para fijar el filtro Nearest).

Catálogo de estilos ampliado de 3 a 6: cyberpunk-neon (prompt puro SD1.5),
low-poly-flat (prompt puro SD1.5), cartoon-cel-shaded (LoRA anime_style_box_sd15 0.7).

Verificación: 11 tests offline del pipeline + suite de presets verde (27 passed).
Prueba real en GPU: mismo "treasure chest" en cyberpunk-neon, low-poly-flat y gameboy
one-shot; gameboy pasa de 17374 colores (crudo) a 4 (paleta Game Boy) auto-pixelizado
directo del pipeline. Detalle en reports/0191.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-27 12:50:30 +02:00
parent 0eefb7cfcd
commit a5748cb147
6 changed files with 835 additions and 7 deletions
@@ -134,6 +134,79 @@ _PRESETS: dict[str, dict] = {
"8GB -> bajar size a 512 (NO matar procesos). El LoRA da el estilo; el post el grid."
),
},
# Cyberpunk neón: ciudad nocturna, luces de neón, glow, alto contraste, atmósfera
# Blade Runner. No hay un LoRA cyberpunk gratis instalado en el servidor; el look se
# logra con PROMPT puro sobre SD1.5 (dreamshaper_8 lo cubre bien) — es un estilo muy
# dirigible por prompt. Sin post (es ilustración con gradientes/glow, NO pixelart;
# pixelizar mataría el brillo). transparent=False para conservar el fondo neón.
"cyberpunk-neon": {
"name": "cyberpunk-neon",
"subject_prefix": "",
"subject_suffix": ", neon-lit, glowing edges, high contrast, futuristic",
"style": "cyberpunk neon art, blade runner aesthetic, glowing neon lights, dark city night, vibrant magenta and cyan glow, rim lighting, reflective surfaces, atmospheric haze, detailed digital painting",
"negative": "daylight, pastel, flat lighting, washed out, low contrast, pixel art, lowres, blurry, deformed, text, watermark, signature",
"checkpoint": "dreamshaper_8.safetensors",
"lora": None,
"lora_strength": 1.0,
"size": 512,
"transparent": False,
"post": {},
"notes": (
"Sin LoRA: no hay un LoRA cyberpunk gratis instalado y no se descargo ninguno "
"gated/de pago. El neón lo da el prompt (glow magenta/cyan, rim lighting, ciudad "
"nocturna) sobre dreamshaper_8 (SD1.5), que rinde bien en este registro. Sin post: "
"el brillo y los gradientes son la identidad del estilo; pixelizar los destruiria. "
"transparent=False para conservar el ambiente neón del fondo."
),
},
# Low-poly flat: estética PS1/PSX y arte 3D minimalista — facetas geométricas, flat
# shading sin gradientes suaves, pocos polígonos, colores planos. PROMPT puro sobre
# SD1.5: el LoRA 3d_render_redmond empuja a render fotorrealista (lo contrario de
# low-poly), asi que se evita a propósito. Sin post (es flat shading limpio, no grid).
"low-poly-flat": {
"name": "low-poly-flat",
"subject_prefix": "",
"subject_suffix": ", low poly, faceted, flat shaded, geometric",
"style": "low poly 3d art, flat shading, faceted geometry, minimal polygons, PS1 PSX aesthetic, clean solid colors, isometric game asset, no gradients, crisp facets",
"negative": "photorealistic, smooth shading, soft gradient, high detail, realistic texture, blurry, noisy, pixel art, deformed, text, watermark, signature",
"checkpoint": "dreamshaper_8.safetensors",
"lora": None,
"lora_strength": 1.0,
"size": 512,
"transparent": True,
"post": {},
"notes": (
"Sin LoRA a propósito: 3d_render_redmond_sd15 (instalado) empuja a render "
"fotorrealista, lo OPUESTO a low-poly. El look faceteado/flat lo da el prompt "
"(low poly, faceted, flat shading, PS1) sobre dreamshaper_8 (SD1.5). Sin post: el "
"flat shading es limpio de por sí, no necesita pixelize. transparent=True porque un "
"asset low-poly suele ir recortado sobre el juego (silueta sólida bien definida)."
),
},
# Cartoon cel-shaded: dibujos animados / anime con sombreado plano por celdas, líneas
# negras gruesas, colores saturados y planos (look toon/Borderlands/Zelda Wind Waker).
# Usa anime_style_box_sd15 (LoRA gratis ya instalado) a fuerza media + prompt cel-shaded.
# Sin post (es ilustración vectorial limpia, no pixelart).
"cartoon-cel-shaded": {
"name": "cartoon-cel-shaded",
"subject_prefix": "",
"subject_suffix": ", cel shaded, bold outlines, flat colors, cartoon",
"style": "cartoon cel-shaded art, bold black outlines, flat color fills, hard cel shadows, vibrant saturated colors, clean vector look, anime toon shading, comic style",
"negative": "photorealistic, soft shading, gradient, realistic texture, painterly, blurry, noisy, pixel art, lowres, grainy, deformed, text, watermark, signature",
"checkpoint": "dreamshaper_8.safetensors",
"lora": "anime_style_box_sd15.safetensors",
"lora_strength": 0.7,
"size": 512,
"transparent": True,
"post": {},
"notes": (
"anime_style_box_sd15.safetensors (gratis, ya instalado en /mnt/2tb) a strength 0.7 "
"empuja el toon/anime; el prompt sella el cel-shading (outlines negros gruesos, "
"sombras duras por celdas, colores planos saturados). SD1.5 (dreamshaper_8). Sin "
"post: el look vectorial limpio no necesita pixelize. transparent=True para recortar "
"la silueta del personaje/objeto cartoon sobre el juego."
),
},
}
@@ -141,7 +214,8 @@ def comfyui_get_gamedev_style_preset(name: str | None = None) -> dict:
"""Devuelve la receta de un style preset gamedev, o el catalogo si name es None.
Args:
name: identificador del estilo ("gameboy", "ghibli", "pixel-art-retro"). Si es
name: identificador del estilo ("gameboy", "ghibli", "pixel-art-retro",
"cyberpunk-neon", "low-poly-flat", "cartoon-cel-shaded"). Si es
None (o cadena vacia), devuelve el catalogo de nombres disponibles en vez de
una receta concreta (discovery). Insensible a mayusculas y a '_' vs '-'.
@@ -65,8 +65,12 @@ def test_golden_ghibli_degrades_to_watercolor_lora():
def test_edge_catalog_when_none():
cat = comfyui_get_gamedev_style_preset(None)
assert set(cat["names"]) == {"gameboy", "ghibli", "pixel-art-retro"}
assert cat["count"] == 3
# Los 3 originales + los 3 ampliados (2026-06-27); el catalogo crece, asi que se
# comprueba inclusion y conteo minimo, no igualdad exacta (evita romper al ampliar).
assert {"gameboy", "ghibli", "pixel-art-retro"} <= set(cat["names"])
assert {"cyberpunk-neon", "low-poly-flat", "cartoon-cel-shaded"} <= set(cat["names"])
assert cat["count"] >= 6
assert cat["count"] == len(cat["names"])
# Cadena vacia tambien devuelve catalogo (discovery).
assert comfyui_get_gamedev_style_preset("") == cat